-
Notifications
You must be signed in to change notification settings - Fork 404
Adds setAppsFlyerConversionData to conveniently track AppsFlyer conversion data
#5936
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
Cursor Agent can help with this pull request. Just |
tonidero
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great to me! 🚢
| if let creative = stringValue(from: data, forKey: "creative") | ||
| ?? stringValue(from: data, forKey: "af_creative") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just curious, for af_ad and af_keywords, we prioritize those keys over the other parameter, but here we prioritize creative over af_creative. Just making sure that's a conscious decission :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, thanks to ChatGPT (and validating that with the AppsFlyer documentation)
rickvdl
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, this should make things a lot easier for developers 🙌
| setReservedAttribute(.mediaSource, value: mediaSource, appUserID: appUserID) | ||
| } | ||
|
|
||
| if let campaign = stringValue(from: data, forKey: "campaign") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With these wrapped in if let's we don't support 'unsetting' or clearing the value. Is that expected? (Same with the data: [AnyHashable: Any]? object itself)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For posterity, linking to my other comment 😄 RevenueCat/purchases-android#2931 (comment)
| /// the `nil` case gets boxed as `Optional<T>.none` inside `Any`, rather than being absent from the dictionary. | ||
| func isNilValue(_ value: Any) -> Bool { | ||
| let mirror = Mirror(reflecting: value) | ||
| return mirror.displayStyle == .optional && mirror.children.isEmpty |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a smart one 😀 Although I would think just doing the following in stringValue(from: data) would work as well (verified it with a playground).
//let value: Optional<String> = "ja"
let value: Optional<Int> = 1
let any = value as Any
print(any)
if let value = any as? String {
print(value)
}
if let intValue = any as? Int {
print(intValue)
}
Did this cause any issues for you?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, for the test case here:
let dataWithNilValues: [AnyHashable: Any] = [
"media_source": nilValue as Any,
"campaign": "valid_campaign"
]it would end up setting $mediaSource to the literal string "nil", which is not what we want. I got the same issue with your code, but maybe I'm doing something wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aha that's interesting, I think the difference is the dictionary here. That's what causing it to loose the generic type information, and it's retrieved as Optional<Any> instead of Optional<String> when it's a nil value for an optional String, and just String when it's a non-nil string.
In my test I defined it without storing it in the dictionary, which is probably why it's smart enough to preserve it's type information.
LGTM then :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about this?
func isNilValue(_ value: Any) -> Bool {
return (value as Any?) == nil
}Casting from Any to Any? always works and preserves nil
8af94b9 to
d8f7c0f
Compare
setAppsFlyerConversionData to conveniently track AppsFlyer conversion data
ajpallares
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! It does make sense to add this convenience API 👍
| } | ||
| if let intValue = value as? Int { return String(intValue) } | ||
| if let doubleValue = value as? Double { return String(Int(doubleValue)) } | ||
| return String(describing: value) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just making sure we want this. This would convert any object into a string.
Motivation
Mini-spec
Description
This PR introduces a new public function
Attribution.setAppsFlyerConversionData(_ data: [AnyHashable: Any]?)that processes AppsFlyer conversion data and sets corresponding RevenueCat subscriber attributes.