diff --git a/.gitignore b/.gitignore index b30abbc3..a8136797 100755 --- a/.gitignore +++ b/.gitignore @@ -92,3 +92,4 @@ atlassian-ide-plugin.xml # exceptions !*adjust-android.jar +!android/libs/adjust*.jar diff --git a/.npmignore b/.npmignore index b41b2dbc..c7edc4bf 100644 --- a/.npmignore +++ b/.npmignore @@ -10,3 +10,7 @@ node_modules /ios/**/*xcuserdata* /ios/**/*xcshareddata* +# Adjust SDK +ext/ +scripts/ +example/ diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..42f9c70f --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,11 @@ +### Version 4.10.0 (1st December 2016) +#### Added +- Initial release of the adjust SDK for React Native. + +#### Native SDKs +- [iOS@v4.10.3][ios_sdk_v4.10.3] +- [Android@v4.10.4][android_sdk_v4.10.4] + +[ios_sdk_v4.10.3]: https://github.com/adjust/ios_sdk/tree/v4.10.3 + +[android_sdk_v4.10.4]: https://github.com/adjust/android_sdk/tree/v4.10.4 diff --git a/README.md b/README.md index 8be4a56a..04cd8b77 100644 --- a/README.md +++ b/README.md @@ -4,18 +4,19 @@ This is the React Native SDK of adjust™. You can read more about adjust™ at ## Table of contents +* [Supported versions](#supported-versions) * [Example app](#example-app) * [Basic integration](#basic-integration) * [Get the SDK](#sdk-get) - * [Add the SDK to your project](#sdk-add) * [Integrate the SDK into your app](#sdk-integrate) * [Adjust logging](#adjust-logging) - * [Google Play Services](#google-play-services) + * [Add Google Play Services](#sdk-gps) + * [Add permissions](#sdk-permissions) + * [Proguard settings](#sdk-proguard) * [Additional features](#additional-features) * [Event tracking](#event-tracking) * [Revenue tracking](#revenue-tracking) * [Revenue deduplication](#revenue-deduplication) - * [In-App Purchase verification](#iap-verification) * [Callback parameters](#callback-parameters) * [Partner parameters](#partner-parameters) * [Session parameters](#session-parameters) @@ -28,46 +29,48 @@ This is the React Native SDK of adjust™. You can read more about adjust™ at * [Offline mode](#offline-mode) * [Event buffering](#event-buffering) * [Background tracking](#background-tracking) - * [Device IDs](#device-ids) * [Push token](#push-token) * [Pre-installed trackers](#pre-installed-trackers) * [Deep linking](#deeplinking) - * [Deep linking](#deeplinking-standard) + * [Standard deep linking scenario](#deeplinking-standard) * [Deferred deep linking scenario](#deeplinking-deferred) * [Reattribution via deep links](#deeplinking-reattribution) * [License](#license) -## Supported versions +## Supported versions - react-native-cli: 1.2.0 - react-native: 0.37.0 -## Example apps +## Example app -There is an example app inside the [`examples` directory][example] +There is an example app inside the [`example` directory][example] ## Basic integration -We will describe the steps to integrate the adjust SDK into your React Native project. You can use any text editor or IDE for React Native development. There are no assumptions made regarding text editors. +We will describe the steps to integrate the adjust SDK into your React Native project. You can use any text editor or IDE +for React Native development. There are no assumptions made regarding development environment. ### Get the SDK -First, download the library from npm: +First, download the library from `npm`: ``` $ npm install react-native-adjust --save ``` -Then you must install the native dependencies: You can use rnpm (now part of react-native core) to add native dependencies automatically then continue the directions below depending on your target OS. +Then you must install the native dependencies. You can use `react-native` cli tool to add native dependencies automatically +and then continue the directions below depending on your target OS. ``` $ react-native link ``` -for **iOS**, you don't need to do much of anything else. +For **iOS**, you don't need to do anything else. -for **Android**, you need to include the native module's package manually. +For **Android**, you need to include the native module's package manually. -- Go to your app's `MainApplication.java` class. It should be located in `./android/app/src/main/java/[your app]/MainApplication.java` +- Go to your app's `MainApplication.java` class. It should be located in +`./android/app/src/main/java/[your app]/MainApplication.java` - There is a method called `getPackages()` that looks like this by default: ```java @Override @@ -77,7 +80,7 @@ protected List getPackages() { ); } ``` -- You'l have to add `new AdjustPackage()` to the list of packages like this: +- You'll have to add the `new AdjustPackage()` to the list of packages like this: ```java @Override protected List getPackages() { @@ -87,7 +90,7 @@ protected List getPackages() { ); } ``` -- Also, don't forget to add the import statement on top of the `MainApplication.java` file: +- Also, don't forget to add the import statement on top of the `MainApplication.java` file: ``` import com.adjust.nativemodule.AdjustPackage; ``` @@ -109,23 +112,26 @@ componentWillMount() { } ``` -Replace `{YourAppToken}` with your app token. You can find this in your dashboard. +Replace `{YourAppToken}` with your app token. You can find this in your adjust dashboard. -Depending on whether you build your app for testing or for production, you must set environment with one of these values: +Depending on whether you build your app for testing or for production, you must set the environment with one of these values: ``` AdjustConfig.EnvironmentSandbox AdjustConfig.EnvironmentProduction ``` -**Important**: This value should be set to `AdjustConfig.EnvironmentSandbox` if and only if you or someone else is testing your app. Make sure to set the environment to `AdjustConfig.EnvironmentProduction` just before you publish the app. Set it back to `AdjustConfig.EnvironmentSandbox` when you start developing and testing it again. - -We use this environment to distinguish between real traffic and test traffic from test devices. It is very important that you keep this value meaningful at all times! This is especially important if you are tracking revenue. +**Important**: This value should be set to `AdjustConfig.EnvironmentSandbox` if and only if you or someone else is testing +your app. Make sure to set the environment to `AdjustConfig.EnvironmentProduction` just before you publish the app. Set it +back to `AdjustConfig.EnvironmentSandbox` when you start developing and testing it again. +We use this environment to distinguish between real traffic and test traffic from test devices. It is very important that +you keep this value meaningful at all times! ### Adjust logging -You can increase or decrease the amount of logs you see in tests by calling `setLogLevel` on your `AdjustConfig` instance with one of the following parameters: +You can increase or decrease the amount of logs you see in tests by calling `setLogLevel` on your `AdjustConfig` instance +with one of the following parameters: ```js adjustConfig.setLogLevel(AdjustConfig.LogLevelVerbose); // enable all logging @@ -137,8 +143,89 @@ adjustConfig.setLogLevel(AdjustConfig.LogLevelAssert); // disable errors as w adjustConfig.setLogLevel(AdjustConfig.LogLevelSuppress); // disable all logging ``` -### Google Play Services +### Add Google Play Services + +Please refer to our Android SDK README page + +Since the 1st of August of 2014, apps in the Google Play Store must use the [Google Advertising ID][google-ad-id] to +uniquely identify devices. To allow the adjust SDK to use the Google Advertising ID, you must integrate the +[Google Play Services][google-play-services]. If you haven't done this yet, follow these steps: + +1. Open your app's `build.gradle` file of your app and find the `dependencies` block. Add the following line: + + ``` + compile 'com.google.android.gms:play-services-analytics:9.8.0' + ``` + +### Add permissions + +The adjust SDK by default adds two permissions to your app's `AndroidManifest.xml` file: + +```xml + + +``` + +General rule of thumb is that if you are targeting the Google Play Store and using Google Play Services in your app, then we just +need `INTERNET` permission: + +```xml + +``` + +If you are **not targeting the Google Play Store**, both of these permissions are needed to be present in your app's +`AndroidManifest.xml` file: + +```xml + + +``` +### Proguard settings + +If you are using Proguard, add these lines to your Proguard file: + +``` +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); +} +-keep class com.adjust.sdk.plugin.MacAddressUtil { + java.lang.String getMacAddress(android.content.Context); +} +-keep class com.adjust.sdk.plugin.AndroidIdUtil { + java.lang.String getAndroidId(android.content.Context); +} +-keep class com.google.android.gms.common.ConnectionResult { + int SUCCESS; +} +-keep class com.google.android.gms.ads.identifier.AdvertisingIdClient { + com.google.android.gms.ads.identifier.AdvertisingIdClient$Info getAdvertisingIdInfo(android.content.Context); +} +-keep class com.google.android.gms.ads.identifier.AdvertisingIdClient$Info { + java.lang.String getId(); + boolean isLimitAdTrackingEnabled(); +} +-keep class android.os.Build { + java.lang.String[] SUPPORTED_ABIS; + java.lang.String CPU_ABI; +} +-keep class android.content.res.Configuration { + android.os.LocaledList getLocales(); + java.util.Locale locale; +} +-keep class android.os.LocaledList { + java.util.Locale get(int); +} +``` + +If you are **not targeting the Google Play Store**, you can remove the `com.google.android.gms` rules. + +**Important**: If you are using an `-overloadaggressively` flag in your Proguard file, then in order for the adjust SDK to +work properly you should consider one of two possible scenarios: + +* Remove `-overloadaggressively` if it is not necessary +* Add a `-useuniqueclassmembernames` flag to your Proguard file ## Additional features @@ -146,7 +233,9 @@ You can take advantage of the following features once the adjust SDK is integrat ### Event tracking -You can use adjust to track all kinds of events. Let's say you want to track every tap on a button. Simply create a new event token in your [dashboard]. Let's say that event token is `abc123`. You can add the following line in your button’s click handler method to track the click: +You can use adjust to track all kinds of events. Let's say you want to track every tap on a button. Simply create a new +event token in your [dashboard]. Let's say that event token is `abc123`. You can add the following line in your button’s +click handler method to track the click: ```js var adjustEvent = new AdjustEvent("abc123"); @@ -155,8 +244,8 @@ Adjust.trackEvent(adjustEvent); ### Revenue tracking -If your users can generate revenue by tapping on advertisements or making In-App Purchases, then you can track those revenues -with events. Let's say a tap is worth €0.01. You could track the revenue event like this: +If your users can generate revenue by tapping on advertisements or making In-App Purchases, then you can track those +revenues with events. Let's say a tap is worth €0.01. You could track the revenue event like this: ```js var adjustEvent = new AdjustEvent("abc123"); @@ -166,18 +255,17 @@ adjustEvent.setRevenue(0.01, "EUR"); Adjust.trackEvent(adjustEvent); ``` -When you set a currency token, adjust will automatically convert the incoming revenues into a reporting revenue of your +When you set a currency token, adjust will automatically convert the incoming revenues into a reporting revenue of your choice. Read more about [currency conversion here][currency-conversion]. - ### Revenue deduplication -You can also add an optional transaction ID to avoid tracking duplicate revenues. The last ten transaction IDs are remembered, -and revenue events with duplicate transaction IDs are skipped. This is especially useful for In-App Purchase tracking. You can -see an example below. +You can also add an optional transaction ID to avoid tracking duplicate revenues. The last ten transaction IDs are +remembered, and revenue events with duplicate transaction IDs are skipped. This is especially useful for In-App Purchase +tracking. You can see an example below. -If you want to track in-app purchases, please make sure to call the `trackEvent` only if the transaction is finished and an item -is purchased. That way you can avoid tracking revenue that is not actually being generated. +If you want to track in-app purchases, please make sure to call the `trackEvent` only if the transaction is finished and an +item is purchased. That way you can avoid tracking revenue that is not actually being generated. ```js var adjustEvent = new AdjustEvent("abc123"); @@ -188,16 +276,16 @@ adjustEvent.setTransactionId("{YourTransactionId}"); Adjust.trackEvent(adjustEvent); ``` -**Note**: Transaction ID is the iOS term, unique identifier for successfully finished Android In-App-Purchases is named **Order ID**. - -### In-App Purchase verification +**Note**: Transaction ID is the iOS term, unique identifier for successfully finished Android In-App-Purchases is named +**Order ID**. ### Callback parameters -You can also register a callback URL for that event in your [dashboard][dashboard] and we will send a GET request to that URL -whenever the event gets tracked. In that case you can also put some key-value pairs in an object and pass it to the `trackEvent` method. We will then append these named parameters to your callback URL. +You can also register a callback URL for that event in your [dashboard][dashboard] and we will send a GET request to that URL whenever the event gets tracked. In that case you can also put some key-value pairs in an object and pass it to the +`trackEvent` method. We will then append these named parameters to your callback URL. -For example, suppose you have registered the URL `http://www.adjust.com/callback` for your event with event token `abc123` and execute the following lines: +For example, suppose you have registered the URL `http://www.adjust.com/callback` for your event with event token `abc123` +and execute the following lines: ```js var adjustEvent = new AdjustEvent("abc123"); @@ -214,22 +302,22 @@ In that case we would track the event and send a request to: http://www.adjust.com/callback?key=value&foo=bar ``` -It should be mentioned that we support a variety of placeholders like `{idfa}` for iOS or `{gps_adid}` for Android that can be -used as parameter values. In the resulting callback the `{idfa}` placeholder would be replaced with the ID for Advertisers of -the current device for iOS and the `{gps_adid}` would be replaced with the Google Advertising ID of the current device for -Android. Also note that we don't store any of your custom parameters, but only append them to your callbacks. If you haven't -registered a callback for an event, these parameters won't even be read. +It should be mentioned that we support a variety of placeholders like `{idfa}` for iOS or `{gps_adid}` for Android that can +be used as parameter values. In the resulting callback the `{idfa}` placeholder would be replaced with the ID for +Advertisers of the current device for iOS and the `{gps_adid}` would be replaced with the Google Advertising ID of the +current device for Android. Also note that we don't store any of your custom parameters, but only append them to your +callbacks. If you haven't registered a callback for an event, these parameters won't even be read. -You can read more about using URL callbacks, including a full list of available values, in our +You can read more about using URL callbacks, including a full list of available values, in our [callbacks guide][callbacks-guide]. ### Partner parameters -Similarly to the callback parameters mentioned above, you can also add parameters that adjust will transmit to the network +Similarly to the callback parameters mentioned above, you can also add parameters that adjust will transmit to the network partners of your choice. You can activate these networks in your adjust dashboard. -This works similarly to the callback parameters mentioned above, but can be added by calling the `addPartnerParameter` method -on your `AdjustEvent` instance. +This works similarly to the callback parameters mentioned above, but can be added by calling the `addPartnerParameter` +method on your `AdjustEvent` instance. ```js var adjustEvent = new AdjustEvent("abc123"); @@ -249,8 +337,8 @@ parameters, you don't need to add them every time, since they will be saved loca there will be no effect. These session parameters can be called before the adjust SDK is launched to make sure they are sent even on install. If you -need to send them with an install, but can only obtain the needed values after launch, it's possible to [delay](#delay-start) -the first launch of the adjust SDK to allow this behaviour. +need to send them with an install, but can only obtain the needed values after launch, it's possible to +[delay](#delay-start) the first launch of the adjust SDK to allow this behaviour. ### Session callback parameters @@ -264,11 +352,11 @@ its value to an event, it's added through a call to method `addSessionCallbackPa Adjust.addSessionCallbackParameter("foo", "bar"); ``` -The session callback parameters will be merged with the callback parameters added to an event. The callback parameters added -to an event have precedence over the session callback parameters. Meaning that, when adding a callback parameter to an event +The session callback parameters will be merged with the callback parameters and added to an event. The callback parameters added +to an event have precedence over the session callback parameters. Meaning that, when adding a callback parameter to an event with the same key to one added from the session, the value that prevails is the callback parameter added to the event. -It's possible to remove a specific session callback parameter by passing the desiring key to the method +It's possible to remove a specific session callback parameter by passing the desiring key to the method `removeSessionCallbackParameter` of the `Adjust` instance: ```js @@ -296,8 +384,8 @@ value to an event, it's added through a call to method `addSessionPartnerParamet Adjust.addSessionPartnerParameter("foo", "bar"); ``` -The session partner parameters will be merged with the partner parameters added to an event. The partner parameters added to -an event have precedence over the session partner parameters. Meaning that, when adding a partner parameter to an event with +The session partner parameters will be merged with the partner parameters and added to an event. The partner parameters added to +an event have precedence over the session partner parameters. Meaning that, when adding a partner parameter to an event with the same key to one added from the session, the value that prevails is the partner parameter added to the event. It's possible to remove a specific session partner parameter by passing the desiring key to the method @@ -325,16 +413,16 @@ Set the initial delay time in seconds with the `setDelayStart` field of the `Adj adjustConfig.setDelayStart(5.5); ``` -In this case this will make the adjust SDK not send the initial install session and any event created for 5.5 seconds. After -this time is expired or if you call `sendFirstPackages()` of the `Adjust` instance in the meanwhile, every session parameter +In this case this will make the adjust SDK not send the initial install session and any event created for 5.5 seconds. After +this time is expired or if you call `sendFirstPackages()` of the `Adjust` instance in the meanwhile, every session parameter will be added to the delayed install session and events and the adjust SDK will resume as usual. **The maximum delay start time of the adjust SDK is 10 seconds**. ### Attribution callback -You can register a listener to be notified of tracker attribution changes. Due to the different sources considered for -attribution, this information cannot by provided synchronously. The simplest way is to create a single anonymous listener +You can register a listener to be notified of tracker attribution changes. Due to the different sources considered for +attribution, this information cannot be provided synchronously. The simplest way is to create a single anonymous listener which is going to be called **each time your user's attribution value changes**: With the `AdjustConfig` instance, before starting the SDK, add the anonymous listener: @@ -373,7 +461,7 @@ Please make sure to consider our [applicable attribution data policies][attribut You can register a callback to be notified of successful and failed tracked events and/or sessions. -Follow the same steps as for attribution callback to implement the following callback function for successfully tracked +Follow the same steps as for attribution callback to implement the following callback function for successfully tracked events: ```js @@ -446,8 +534,9 @@ adjustConfig.setSessionTrackingFailedCallbackListener(function(sessionFailure) { Adjust.create(adjustConfig); ``` -The callback functions will be called after the SDK tries to send a package to the server. Within the callback you have access -to a response data object specifically for the callback. Here is a quick summary of the session response data properties: +The callback functions will be called after the SDK tries to send a package to the server. Within the callback you have +access to a response data object specifically for the callback. Here is a quick summary of the session response data +properties: - `var message` the message from the server or the error logged by the SDK. - `var timestamp` timestamp from the server. @@ -464,21 +553,21 @@ And both event and session failed objects also contain: ### Disable tracking -You can disable the adjust SDK from tracking by invoking the method `setEnabled` of the `Adjust` instance with the enabled +You can disable the adjust SDK from tracking by invoking the method `setEnabled` of the `Adjust` instance with the enabled parameter as `false`. This setting is **remembered between sessions**, but it can only be activated after the first session. ```js Adjust.setEnabled(false); ``` -You can verify if the adjust SDK is currently active with the method `isEnabled` of the `Adjust` instance. It is always +You can verify if the adjust SDK is currently active with the method `isEnabled` of the `Adjust` instance. It is always possible to activate the adjust SDK by invoking `setEnabled` with the parameter set to `true`. ### Offline mode -You can put the adjust SDK in offline mode to suspend transmission to our servers while retaining tracked data to be sent -later. When in offline mode, all information is saved in a file, so be careful not to trigger too many events while in offline -mode. +You can put the adjust SDK in offline mode to suspend transmission to our servers while retaining tracked data to be sent +later. When in offline mode, all information is saved in a file, so be careful not to trigger too many events while in +offline mode. You can activate offline mode by calling the method `setOfflineMode` of the `Adjust` instance with the parameter `true`. @@ -486,7 +575,7 @@ You can activate offline mode by calling the method `setOfflineMode` of the `Adj Adjust.setOfflineMode(true); ``` -Conversely, you can deactivate offline mode by calling `setOfflineMode` with `false`. When the adjust SDK is put back in +Conversely, you can deactivate offline mode by calling `setOfflineMode` with `false`. When the adjust SDK is put back in online mode, all saved information is send to our servers with the correct time information. Unlike disabling tracking, **this setting is not remembered** between sessions. This means that the SDK is in online mode @@ -494,7 +583,7 @@ whenever it is started, even if the app was terminated in offline mode. ### Event buffering -If your app makes heavy use of event tracking, you might want to delay some HTTP requests in order to send them in one batch +If your app makes heavy use of event tracking, you might want to delay some HTTP requests in order to send them in one batch every minute. You can enable event buffering with your `AdjustConfig` instance by calling `setEventBufferingEnabled` method: ```js @@ -507,7 +596,7 @@ Adjust.create(adjustConfig); ### Background tracking -The default behaviour of the adjust SDK is to **pause sending HTTP requests while the app is in the background**. You can +The default behaviour of the adjust SDK is to **pause sending HTTP requests while the app is in the background**. You can change this in your `AdjustConfig` instance by calling `setSendInBackground` method: ```js @@ -520,37 +609,9 @@ Adjust.create(adjustConfig); If nothing is set, sending in background is **disabled by default**. -### Device IDs - -Certain services (such as Google Analytics) require you to coordinate Device and Client IDs in order to prevent duplicate -reporting. - -### Android - -If you need to obtain the Google Advertising ID, you can call the function `getGoogleAdId`. To get it in the callback method -you pass to the call: - -```js -Adjust.getGoogleAdId(function(googleAdId) { - // Use googleAdId value. -}); -``` - -Inside the callback method you will have access to the Google Advertising ID as the variable `googleAdId`. - -### iOS - -To obtain the IDFA, call the function `getIdfa` in the same way as the method `getGoogleAdId`: - -```js -Adjust.getIdfa(function(idfa) { - // Use idfa value. -}); -``` - ### Push token -To send us the push notification token, add the following call to Adjust **whenever you get your token in the app or +To send us the push notification token, add the following call to Adjust **whenever you get your token in the app or when it gets updated**: ```js @@ -568,11 +629,11 @@ If you want to use the adjust SDK to recognize users that found your app pre-ins var adjustConfig = new AdjustConfig(appToken, environment); adjustConfig.setDefaultTracker("{TrackerToken}"); - + Adjust.create(adjustConfig); ``` - Replace `{TrackerToken}` with the tracker token you created in step 2. Please note that the dashboard displays a tracker + Replace `{TrackerToken}` with the tracker token you created in step 2. Please note that the dashboard displays a tracker URL (including `http://app.adjust.com/`). In your source code, you should specify only the six-character token and not the entire URL. @@ -582,45 +643,32 @@ If you want to use the adjust SDK to recognize users that found your app pre-ins Default tracker: 'abc123' ``` -### Deep linking +### Deep linking -To support deep linking in Android, the app's `AndroidManifest.xml` file will need to be modified. Please refer to this [page of our Android SDK][android-sdk-deeplink] for the needed modifications to `AndroidManifest.xml`. +If you are using the adjust tracker URL with an option to deep link into your app from the URL, there is the possibility to +get info about the deep link URL and its content. Hitting the URL can happen when the user has your app already installed +(standard deep linking scenario) or if they don't have the app on their device (deferred deep linking scenario). -To support deep linking in iOS, the app's `info.plist` file will need to be modified. Please refer to this [page of our iOS SDK][ios-sdk-deeplink] for the needed modifications to `info.plist`. +### Standard deep linking scenario -After that, please refer to this page of the [React Native offical docs][rn-linking] for instructions on how to support both platforms. In basic terms, your React component will have to add `Linking` component, as follows: -```js -import { - StyleSheet, - Platform, - Text, - View, - ToolbarAndroid, - Linking //This is important -} from 'react-native'; -``` +To support deep linking in Android, the app's `AndroidManifest.xml` file will need to be modified. Please refer to this +[page of our Android SDK][android-sdk-deeplink] for the needed modifications to `AndroidManifest.xml`. -And then on your React component you'll be able to listen to the events on `Linking` as follows: -```js -componentDidMount() { - Linking.addEventListener('url', this._handleOpenURL); -}, -componentWillUnmount() { - Linking.removeEventListener('url', this._handleOpenURL); -}, -_handleOpenURL(event) { - console.log(event.url); -} -``` +To support deep linking in iOS 8 or earlier, the app's `Info.plist` file will need to be modified. Please refer to this +[page of our iOS SDK][ios-sdk-deeplink-early] for the needed modifications to `Info.plist`. + +To support deep linking in iOS 9 or later, your app would have to handle Universal Links. Please refer to this +[page of our iOS SDK][ios-sdk-deeplink-late] for the needed modifications. -Please refer to the [React Native offical docs][rn-linking] for the detailed steps. +After that, refer to this page of the [React Native offical docs][rn-linking] for instructions on how to support both +platforms and obtain deep link URL in your JavaScript code. -### Deferred deep linking +### Deferred deep linking scenario While deferred deep linking is not supported out of the box on Android and iOS, our adjust SDK makes it possible. - -In order to get info about the URL content in a deferred deep linking scenario, you should set a callback method on the -`AdjustConfig` object which will receive one parameter where the content of the URL will be delivered. You should set this + +In order to get info about the URL content in a deferred deep linking scenario, you should set a callback method on the +`AdjustConfig` object which will receive one parameter where the content of the URL will be delivered. You should set this method on the config object by calling the method `setDeeplinkCallbackListener`: ```js @@ -633,8 +681,8 @@ adjustConfig.setDeferredDeeplinkCallbackListener(function(deeplink) { Adjust.create(adjustConfig); ``` -In deferred deep linking scenario, there is one additional setting which can be set on the `AdjustConfig` object. Once the -adjust SDK gets the deferred deep link info, we are offering you the possibility to choose whether our SDK should open this +In the deferred deep linking scenario, there is one additional setting which can be set on the `AdjustConfig` object. Once the +adjust SDK gets the deferred deep link info, we are offering you the possibility to choose whether our SDK should open this URL or not. You can choose to set this option by calling the `setShouldLaunchDeeplink` method on the config object: @@ -655,41 +703,82 @@ If nothing is set, **the adjust SDK will always try to launch the URL by default ### Reattribution via deep links -Adjust enables you to run re-engagement campaigns by using deep links. For more information on this, please check our +Adjust enables you to run re-engagement campaigns by using deep links. For more information on this, please check our [official docs][reattribution-with-deeplinks]. -If you are using this feature, in order for your user to be properly reattributed, you need to make one additional call to the -adjust SDK in your app. +If you are using this feature, in order for your user to be properly reattributed, you need to make one additional call to +the adjust SDK in your app. Once you have received deep link content information in your app, add a call to `appWillOpenUrl` +method of the `Adjust` instance. By making this call, the adjust SDK will try to find if there is any new attribution info +inside of the deep link and if any, it will be sent to the adjust backend. If your user should be reattributed due to a +click on the adjust tracker URL with deep link content in it, you will see the [attribution callback](#attribution-callback) +in your app being triggered with new attribution info for this user. + +Call to the `appWillOpenUrl` method in a React component for **Android** would look like this: -Once you have received deep link content information in your app, add a call to `appWillOpenUrl` method of the `Adjust` -instance. By making this call, the adjust SDK will try to find if there is any new attribution info inside of the deep link -and if any, it will be sent to the adjust backend. If your user should be reattributed due to a click on the adjust tracker -URL with deep link content in it, you will see the [attribution callback](#attribution-callback) in your app being triggered -with new attribution info for this user. +```js +componentDidMount() { + const url = Linking.getInitialURL().then(url => { + if (url) { + Adjust.appWillOpenUrl(url); + } + }); +} +``` -Call to the `appWillOpenUrl` method in a React component would look like this: +And like the following for **iOS**: ```js componentDidMount() { Linking.addEventListener('url', this._handleOpenURL); -}, +} + componentWillUnmount() { Linking.removeEventListener('url', this._handleOpenURL); -}, -_handleOpenURL(event) { - console.log(event.url); +} +_handleOpenURL(event) { Adjust.appWillOpenUrl(event.url); } ``` +**Warning:** There is a bug in version 1.2.0 of React Native where deep link URL delivery to JavaScript only works if the +app is opened in the background already. If the app is closed and not running in the background, opening it by click on an +universal link **will not deliver universal link URL info to your callback method in JavaScript**. This will also cause the +call to `Adjust.appWillOpenUrl` to not be made, and if reattribution for this user should have happened, it won't. + +If you are following the [React Native official linking docs][rn-linking] for iOS, you will encounter this issue. + +As a quick fix, you can bypass the JavaScript layer and add a call to our SDK directly in your `AppDelegate.m`. It would +look like this: + +```objc +#include "Adjust.h" + +// ... + +- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation { + [Adjust appWillOpenUrl:url]; + + return YES; +} + +- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray *restorableObjects))restorationHandler { + if ([[userActivity activityType] isEqualToString:NSUserActivityTypeBrowsingWeb]) { + [Adjust appWillOpenUrl:[userActivity webpageURL]]; + } + + return YES; +} +``` + [dashboard]: http://adjust.com [adjust.com]: http://adjust.com -[example]: http://github.com/adjust/ios_sdk/tree/master/examples +[example]: ./example [npm-repo]: https://www.npmjs.com/package/react-native-adjust -[google-ad-id]: https://developer.android.com/google/play-services/id.html +[rn-linking]: https://facebook.github.io/react-native/docs/linking.html +[google-ad-id]: https://support.google.com/googleplay/android-developer/answer/6048248?hl=en [enable-ulinks]: https://github.com/adjust/ios_sdk#deeplinking-setup-new [event-tracking]: https://docs.adjust.com/en/event-tracking [callbacks-guide]: https://docs.adjust.com/en/callbacks @@ -699,16 +788,18 @@ _handleOpenURL(event) { [google-launch-modes]: http://developer.android.com/guide/topics/manifest/activity-element.html#lmode [currency-conversion]: https://docs.adjust.com/en/event-tracking/#tracking-purchases-in-different-currencies [google-play-services]: http://developer.android.com/google/play-services/index.html +[android-sdk-deeplink]: https://github.com/adjust/android_sdk#deeplinking-standard +[google-play-services]: http://developer.android.com/google/play-services/setup.html +[ios-sdk-deeplink-late]: https://github.com/adjust/ios_sdk#-deep-linking-on-ios-9-and-later +[ios-sdk-deeplink-early]: https://github.com/adjust/ios_sdk#-deep-linking-on-ios-8-and-earlier -[android-sdk-deeplink]: https://github.com/adjust/android_sdk#deeplinking-standard [reattribution-with-deeplinks]: https://docs.adjust.com/en/deeplinking/#manually-appending-attribution-data-to-a-deep-link -[rn-linking]: https://facebook.github.io/react-native/docs/linking.html ## License The adjust SDK is licensed under the MIT License. -Copyright (c) 2012-2016 adjust GmbH, +Copyright (c) 2012-2016 adjust GmbH, http://www.adjust.com Permission is hereby granted, free of charge, to any person obtaining a copy of diff --git a/android/libs/adjust-4.10.4.jar b/android/libs/adjust-4.10.4.jar new file mode 100644 index 00000000..b9b15b2c Binary files /dev/null and b/android/libs/adjust-4.10.4.jar differ diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml old mode 100755 new mode 100644 index 6024e180..92354ea6 --- a/android/src/main/AndroidManifest.xml +++ b/android/src/main/AndroidManifest.xml @@ -1,18 +1,15 @@ + - - - - - - - - - - - - - + + + + + + + diff --git a/android/src/main/java/com/adjust/sdk/Adjust.java b/android/src/main/java/com/adjust/sdk/Adjust.java index 2645893c..a4856d17 100755 --- a/android/src/main/java/com/adjust/sdk/Adjust.java +++ b/android/src/main/java/com/adjust/sdk/Adjust.java @@ -9,18 +9,17 @@ package com.adjust.nativemodule; -import android.view.Gravity; - -import com.facebook.common.logging.FLog; import com.facebook.react.bridge.*; import com.facebook.react.modules.core.*; -import javax.annotation.Nullable; -import android.util.Log; -import android.net.Uri; + import java.util.Map; import java.util.HashMap; import java.util.Map.Entry; +import android.net.Uri; + +import javax.annotation.Nullable; + import com.adjust.sdk.*; public class Adjust extends ReactContextBaseJavaModule @@ -55,10 +54,7 @@ public void initialize() { @Override public void onHostPause() { - } - - @Override - public void onHostDestroy() { + com.adjust.sdk.Adjust.onPause(); } @Override @@ -66,6 +62,9 @@ public void onHostResume() { com.adjust.sdk.Adjust.onResume(); } + @Override + public void onHostDestroy() {} + @Override public void onAttributionChanged(AdjustAttribution attribution) { sendEvent(getReactApplicationContext(), "adjust_attribution", AdjustUtil.attributionToMap(attribution)); @@ -112,162 +111,158 @@ public void create(ReadableMap mapConfig) { double delayStart = 0.0; boolean isLogLevelSuppress = false; - //check for isLogLevelSuppress + // Check for isLogLevelSuppress. if (!mapConfig.isNull("logLevel")) { logLevel = mapConfig.getString("logLevel"); - if(logLevel.equals("SUPPRESS")) { + if (logLevel.equals("SUPPRESS")) { isLogLevelSuppress = true; } } - //check for appToken and environment + // Check for appToken and environment. appToken = mapConfig.getString("appToken"); environment = mapConfig.getString("environment"); - final AdjustConfig adjustConfig - = new AdjustConfig( - getReactApplicationContext(), - appToken, - environment, - isLogLevelSuppress); - - - if (adjustConfig.isValid()) { - // Log level - if (!mapConfig.isNull("logLevel")) { - logLevel = mapConfig.getString("logLevel"); - - if (logLevel.equals("VERBOSE")) { - adjustConfig.setLogLevel(LogLevel.VERBOSE); - } else if (logLevel.equals("DEBUG")) { - adjustConfig.setLogLevel(LogLevel.DEBUG); - } else if (logLevel.equals("INFO")) { - adjustConfig.setLogLevel(LogLevel.INFO); - } else if (logLevel.equals("WARN")) { - adjustConfig.setLogLevel(LogLevel.WARN); - } else if (logLevel.equals("ERROR")) { - adjustConfig.setLogLevel(LogLevel.ERROR); - } else if (logLevel.equals("ASSERT")) { - adjustConfig.setLogLevel(LogLevel.ASSERT); - } else if (logLevel.equals("SUPPRESS")) { - adjustConfig.setLogLevel(LogLevel.SUPRESS); - } else { - adjustConfig.setLogLevel(LogLevel.INFO); - } - } + final AdjustConfig adjustConfig = new AdjustConfig(getReactApplicationContext(), appToken, environment, isLogLevelSuppress); - // Event buffering - if(!mapConfig.isNull("eventBufferingEnabled")) { - eventBufferingEnabled = mapConfig.getBoolean("eventBufferingEnabled"); - adjustConfig.setEventBufferingEnabled(eventBufferingEnabled); - } + if (!adjustConfig.isValid()) { + return; + } - // SDK prefix - if (!mapConfig.isNull("sdkPrefix")) { - sdkPrefix = mapConfig.getString("sdkPrefix"); - adjustConfig.setSdkPrefix(sdkPrefix); - } + // Log level + if (!mapConfig.isNull("logLevel")) { + logLevel = mapConfig.getString("logLevel"); - // Main process name - if (!mapConfig.isNull("processName")) { - processName = mapConfig.getString("processName"); - adjustConfig.setProcessName(processName); + if (logLevel.equals("VERBOSE")) { + adjustConfig.setLogLevel(LogLevel.VERBOSE); + } else if (logLevel.equals("DEBUG")) { + adjustConfig.setLogLevel(LogLevel.DEBUG); + } else if (logLevel.equals("INFO")) { + adjustConfig.setLogLevel(LogLevel.INFO); + } else if (logLevel.equals("WARN")) { + adjustConfig.setLogLevel(LogLevel.WARN); + } else if (logLevel.equals("ERROR")) { + adjustConfig.setLogLevel(LogLevel.ERROR); + } else if (logLevel.equals("ASSERT")) { + adjustConfig.setLogLevel(LogLevel.ASSERT); + } else if (logLevel.equals("SUPPRESS")) { + adjustConfig.setLogLevel(LogLevel.SUPRESS); + } else { + adjustConfig.setLogLevel(LogLevel.INFO); } + } - // Default tracker - if (!mapConfig.isNull("defaultTracker")) { - defaultTracker = mapConfig.getString("defaultTracker"); - adjustConfig.setDefaultTracker(defaultTracker); - } + // Event buffering + if(!mapConfig.isNull("eventBufferingEnabled")) { + eventBufferingEnabled = mapConfig.getBoolean("eventBufferingEnabled"); + adjustConfig.setEventBufferingEnabled(eventBufferingEnabled); + } - // User agent - if (!mapConfig.isNull("userAgent") ) { - userAgent = mapConfig.getString("userAgent"); - adjustConfig.setUserAgent(userAgent); - } + // SDK prefix + if (!mapConfig.isNull("sdkPrefix")) { + sdkPrefix = mapConfig.getString("sdkPrefix"); + adjustConfig.setSdkPrefix(sdkPrefix); + } - // Background tracking - if(!mapConfig.isNull("sendInBackground")) { - sendInBackground = mapConfig.getBoolean("sendInBackground"); - adjustConfig.setSendInBackground(sendInBackground); - } + // Main process name + if (!mapConfig.isNull("processName")) { + processName = mapConfig.getString("processName"); + adjustConfig.setProcessName(processName); + } - // Launching deferred deep link - if(!mapConfig.isNull("shouldLaunchDeeplink")) { - shouldLaunchDeeplink = mapConfig.getBoolean("shouldLaunchDeeplink"); - this.shouldLaunchDeeplink = shouldLaunchDeeplink; - } + // Default tracker + if (!mapConfig.isNull("defaultTracker")) { + defaultTracker = mapConfig.getString("defaultTracker"); + adjustConfig.setDefaultTracker(defaultTracker); + } - // Delayed start - if(!mapConfig.isNull("delayStart")) { - delayStart = mapConfig.getDouble("delayStart"); - adjustConfig.setDelayStart(delayStart); - } + // User agent + if (!mapConfig.isNull("userAgent") ) { + userAgent = mapConfig.getString("userAgent"); + adjustConfig.setUserAgent(userAgent); + } - // Attribution callback - if (attributionCallback) { - adjustConfig.setOnAttributionChangedListener(this); - } + // Background tracking + if (!mapConfig.isNull("sendInBackground")) { + sendInBackground = mapConfig.getBoolean("sendInBackground"); + adjustConfig.setSendInBackground(sendInBackground); + } - // Event tracking succeeded callback - if (eventTrackingSucceededCallback) { - adjustConfig.setOnEventTrackingSucceededListener(this); - } + // Launching deferred deep link + if (!mapConfig.isNull("shouldLaunchDeeplink")) { + shouldLaunchDeeplink = mapConfig.getBoolean("shouldLaunchDeeplink"); + this.shouldLaunchDeeplink = shouldLaunchDeeplink; + } - // Event tracking failed callback - if (eventTrackingFailedCallback) { - adjustConfig.setOnEventTrackingFailedListener(this); - } + // Delayed start + if (!mapConfig.isNull("delayStart")) { + delayStart = mapConfig.getDouble("delayStart"); + adjustConfig.setDelayStart(delayStart); + } - // Session tracking succeeded callback - if (sessionTrackingSucceededCallback) { - adjustConfig.setOnSessionTrackingSucceededListener(this); - } + // Attribution callback + if (attributionCallback) { + adjustConfig.setOnAttributionChangedListener(this); + } - // Session tracking failed callback - if (sessionTrackingFailedCallback) { - adjustConfig.setOnSessionTrackingFailedListener(this); - } + // Event tracking succeeded callback + if (eventTrackingSucceededCallback) { + adjustConfig.setOnEventTrackingSucceededListener(this); + } - // Deferred deeplink callback listener - if (deferredDeeplinkCallback) { - adjustConfig.setOnDeeplinkResponseListener(this); - } + // Event tracking failed callback + if (eventTrackingFailedCallback) { + adjustConfig.setOnEventTrackingFailedListener(this); + } + + // Session tracking succeeded callback + if (sessionTrackingSucceededCallback) { + adjustConfig.setOnSessionTrackingSucceededListener(this); + } + + // Session tracking failed callback + if (sessionTrackingFailedCallback) { + adjustConfig.setOnSessionTrackingFailedListener(this); + } - com.adjust.sdk.Adjust.onCreate(adjustConfig); - com.adjust.sdk.Adjust.onResume(); + // Deferred deeplink callback listener + if (deferredDeeplinkCallback) { + adjustConfig.setOnDeeplinkResponseListener(this); } + + com.adjust.sdk.Adjust.onCreate(adjustConfig); + com.adjust.sdk.Adjust.onResume(); } @ReactMethod public void trackEvent(ReadableMap mapEvent) { final String eventToken = mapEvent.getString("eventToken"); - final Double revenue = mapEvent.getDouble("revenue"); final String currency = mapEvent.getString("currency"); + final String transactionId = mapEvent.getString("transactionId"); final Map callbackParameters = AdjustUtil.toMap(mapEvent.getMap("callbackParameters")); final Map partnerParameters = AdjustUtil.toMap(mapEvent.getMap("partnerParameters")); AdjustEvent event = new AdjustEvent(eventToken); - if(event.isValid()) { - event.setRevenue(revenue, currency); + + if (event.isValid()) { + if (!mapEvent.isNull("revenue")) { + event.setRevenue(mapEvent.getDouble("revenue"), currency); + } - if(callbackParameters != null) { + if (null != callbackParameters) { for (Map.Entry entry : callbackParameters.entrySet()) { event.addCallbackParameter(entry.getKey(), entry.getValue().toString()); } } - if(partnerParameters != null) { + if (null != partnerParameters) { for (Map.Entry entry : partnerParameters.entrySet()) { event.addPartnerParameter(entry.getKey(), entry.getValue().toString()); } } - if(!mapEvent.isNull("transactionId")) { - final String transactionId - = mapEvent.getString("transactionId"); - + if (null != transactionId) { event.setOrderId(transactionId); } @@ -371,42 +366,9 @@ public void setDeferredDeeplinkCallbackListener() { this.deferredDeeplinkCallback = true; } - @ReactMethod - public void clearAttributionCallbackListener() { - this.attributionCallback = false; - } - - @ReactMethod - public void clearEventTrackingSucceededCallbackListener() { - this.eventTrackingSucceededCallback = false; - } - - @ReactMethod - public void clearEventTrackingFailedCallbackListener() { - this.eventTrackingFailedCallback = false; - } - - @ReactMethod - public void clearSessionTrackingSucceededCallbackListener() { - this.sessionTrackingSucceededCallback = false; - } - - @ReactMethod - public void clearSessionTrackingFailedCallbackListener() { - this.sessionTrackingFailedCallback = false; - } - - @ReactMethod - public void clearDeferredDeeplinkCallbackListener() { - this.deferredDeeplinkCallback = false; - } - - private void sendEvent(ReactContext reactContext, - String eventName, - @Nullable WritableMap params) { + private void sendEvent(ReactContext reactContext, String eventName, @Nullable WritableMap params) { reactContext .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) .emit(eventName, params); } - } diff --git a/android/src/main/java/com/adjust/sdk/AdjustUtil.java b/android/src/main/java/com/adjust/sdk/AdjustUtil.java index b8ee20d6..c71f8b19 100644 --- a/android/src/main/java/com/adjust/sdk/AdjustUtil.java +++ b/android/src/main/java/com/adjust/sdk/AdjustUtil.java @@ -9,73 +9,121 @@ package com.adjust.nativemodule; -import com.facebook.react.modules.core.*; -import com.facebook.react.bridge.*; - -import java.util.ArrayList; +import java.util.Map; +import java.util.List; import android.net.Uri; import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.ArrayList; + +import javax.annotation.Nullable; + +import com.facebook.react.bridge.*; +import com.facebook.react.modules.core.*; + import com.adjust.sdk.*; -import javax.annotation.Nullable; +final class AdjustUtil { + private static final String ATTRIBUTION_TRACKER_TOKEN = "trackerToken"; + private static final String ATTRIBUTION_TRACKER_NAME = "trackerName"; + private static final String ATTRIBUTION_NETWORK = "network"; + private static final String ATTRIBUTION_CAMPAIGN = "campaign"; + private static final String ATTRIBUTION_ADGROUP = "adgroup"; + private static final String ATTRIBUTION_CREATIVE = "creative"; + private static final String ATTRIBUTION_CLICK_LABEL = "clickLabel"; + + private static final String EVENT_SUCCESS_MESSAGE = "message"; + private static final String EVENT_SUCCESS_TIMESTAMP = "timestamp"; + private static final String EVENT_SUCCESS_ADID = "adid"; + private static final String EVENT_SUCCESS_EVENT_TOKEN = "eventToken"; + private static final String EVENT_SUCCESS_JSON_RESPONSE = "jsonResponse"; + + private static final String EVENT_FAILED_MESSAGE = "message"; + private static final String EVENT_FAILED_TIMESTAMP = "timestamp"; + private static final String EVENT_FAILED_ADID = "adid"; + private static final String EVENT_FAILED_EVENT_TOKEN = "eventToken"; + private static final String EVENT_FAILED_WILL_RETRY = "willRetry"; + private static final String EVENT_FAILED_JSON_RESPONSE = "jsonResponse"; + + private static final String SESSION_SUCCESS_MESSAGE = "message"; + private static final String SESSION_SUCCESS_TIMESTAMP = "timestamp"; + private static final String SESSION_SUCCESS_ADID = "adid"; + private static final String SESSION_SUCCESS_JSON_RESPONSE = "jsonResponse"; + + private static final String SESSION_FAILED_MESSAGE = "message"; + private static final String SESSION_FAILED_TIMESTAMP = "timestamp"; + private static final String SESSION_FAILED_ADID = "adid"; + private static final String SESSION_FAILED_WILL_RETRY = "willRetry"; + private static final String SESSION_FAILED_JSON_RESPONSE = "jsonResponse"; -/** - * toMap converts a {@link ReadableMap} into a HashMap. - * - * @param readableMap The ReadableMap to be conveted. - * @return A HashMap containing the data that was in the ReadableMap. - */ + public static WritableMap attributionToMap(AdjustAttribution attribution) { + WritableMap map = Arguments.createMap(); -final class AdjustUtil { - /** - * toObject extracts a value from a {@link ReadableMap} by its key, - * and returns a POJO representing that object. - * - * @param readableMap The Map to containing the value to be converted - * @param key The key for the value to be converted - * @return The converted POJO - */ - public static Object toObject(@Nullable ReadableMap readableMap, String key) { - if (readableMap == null) { - return null; - } + map.putString(ATTRIBUTION_TRACKER_TOKEN, null != attribution.trackerToken ? attribution.trackerToken : ""); + map.putString(ATTRIBUTION_TRACKER_NAME, null != attribution.trackerName ? attribution.trackerName : ""); + map.putString(ATTRIBUTION_NETWORK, null != attribution.network ? attribution.network : ""); + map.putString(ATTRIBUTION_CAMPAIGN, null != attribution.campaign ? attribution.campaign : ""); + map.putString(ATTRIBUTION_ADGROUP, null != attribution.adgroup ? attribution.adgroup : ""); + map.putString(ATTRIBUTION_CREATIVE, null != attribution.creative ? attribution.creative : ""); + map.putString(ATTRIBUTION_CLICK_LABEL, null != attribution.clickLabel ? attribution.clickLabel : ""); - Object result; + return map; + } - ReadableType readableType = readableMap.getType(key); - switch (readableType) { - case Null: - result = key; - break; - case Boolean: - result = readableMap.getBoolean(key); - break; - case Number: - // Can be int or double. - double tmp = readableMap.getDouble(key); - if (tmp == (int) tmp) { - result = (int) tmp; - } else { - result = tmp; - } - break; - case String: - result = readableMap.getString(key); - break; - case Map: - result = toMap(readableMap.getMap(key)); - break; - case Array: - result = toList(readableMap.getArray(key)); - break; - default: - throw new IllegalArgumentException("Could not convert object with key: " + key + "."); - } + public static WritableMap eventSuccessToMap(AdjustEventSuccess eventSuccess) { + WritableMap map = Arguments.createMap(); - return result; - } + map.putString(EVENT_SUCCESS_MESSAGE, null != eventSuccess.message ? eventSuccess.message : ""); + map.putString(EVENT_SUCCESS_TIMESTAMP, null != eventSuccess.timestamp ? eventSuccess.timestamp : ""); + map.putString(EVENT_SUCCESS_ADID, null != eventSuccess.adid ? eventSuccess.adid : ""); + map.putString(EVENT_SUCCESS_EVENT_TOKEN, null != eventSuccess.eventToken ? eventSuccess.eventToken : ""); + map.putString(EVENT_SUCCESS_JSON_RESPONSE, null != eventSuccess.jsonResponse ? eventSuccess.jsonResponse.toString() : ""); + + return map; + } + + public static WritableMap eventFailureToMap(AdjustEventFailure eventFailure) { + WritableMap map = Arguments.createMap(); + + map.putString(EVENT_FAILED_MESSAGE, null != eventFailure.message ? eventFailure.message : ""); + map.putString(EVENT_FAILED_TIMESTAMP, null != eventFailure.timestamp ? eventFailure.timestamp : ""); + map.putString(EVENT_FAILED_ADID, null != eventFailure.adid ? eventFailure.adid : ""); + map.putString(EVENT_FAILED_EVENT_TOKEN, null != eventFailure.eventToken ? eventFailure.eventToken : ""); + map.putString(EVENT_FAILED_WILL_RETRY, eventFailure.willRetry ? "true" : "false"); + map.putString(EVENT_FAILED_JSON_RESPONSE, null != eventFailure.jsonResponse ? eventFailure.jsonResponse.toString() : ""); + + return map; + } + + public static WritableMap sessionSuccessToMap(AdjustSessionSuccess sessionSuccess) { + WritableMap map = Arguments.createMap(); + + map.putString(SESSION_SUCCESS_MESSAGE, null != sessionSuccess.message ? sessionSuccess.message : ""); + map.putString(SESSION_SUCCESS_TIMESTAMP, null != sessionSuccess.timestamp ? sessionSuccess.timestamp : ""); + map.putString(SESSION_SUCCESS_ADID, null != sessionSuccess.adid ? sessionSuccess.adid : ""); + map.putString(SESSION_SUCCESS_JSON_RESPONSE, null != sessionSuccess.jsonResponse ? sessionSuccess.jsonResponse.toString() : ""); + + return map; + } + + public static WritableMap sessionFailureToMap(AdjustSessionFailure sessionFailure) { + WritableMap map = Arguments.createMap(); + + map.putString(SESSION_FAILED_MESSAGE, null != sessionFailure.message ? sessionFailure.message : ""); + map.putString(SESSION_FAILED_TIMESTAMP, null != sessionFailure.timestamp ? sessionFailure.timestamp : ""); + map.putString(SESSION_FAILED_ADID, null != sessionFailure.adid ? sessionFailure.adid : ""); + map.putString(SESSION_FAILED_WILL_RETRY, sessionFailure.willRetry ? "true" : "false"); + map.putString(SESSION_FAILED_JSON_RESPONSE, null != sessionFailure.jsonResponse ? sessionFailure.jsonResponse.toString() : ""); + + return map; + } + + public static WritableMap deferredDeeplinkToMap(Uri uri) { + WritableMap map = Arguments.createMap(); + + map.putString("uri", uri.toString()); + + return map; + } /** * toMap converts a {@link ReadableMap} into a HashMap. @@ -86,21 +134,30 @@ public static Object toObject(@Nullable ReadableMap readableMap, String key) { public static Map toMap(@Nullable ReadableMap readableMap) { if (readableMap == null) { return null; - } + } com.facebook.react.bridge.ReadableMapKeySetIterator iterator = readableMap.keySetIterator(); + if (!iterator.hasNextKey()) { return null; - } + } Map result = new HashMap<>(); + while (iterator.hasNextKey()) { String key = iterator.nextKey(); - result.put(key, toObject(readableMap, key)); - } + String value = toObject(readableMap, key).toString(); + + if (value == null) { + AdjustFactory.getLogger().warn("Null parameter inside key-value pair with key: " + key); + continue; + } + + result.put(key, value); + } return result; - } + } /** * toList converts a {@link ReadableArray} into an ArrayList. @@ -111,14 +168,15 @@ public static Map toMap(@Nullable ReadableMap readableMap) { public static List toList(@Nullable ReadableArray readableArray) { if (readableArray == null) { return null; - } + } List result = new ArrayList<>(readableArray.size()); + for (int index = 0; index < readableArray.size(); index++) { ReadableType readableType = readableArray.getType(index); + switch (readableType) { case Null: - result.add(String.valueOf(index)); break; case Boolean: result.add(readableArray.getBoolean(index)); @@ -126,11 +184,13 @@ public static List toList(@Nullable ReadableArray readableArray) { case Number: // Can be int or double. double tmp = readableArray.getDouble(index); - if (tmp == (int) tmp) { - result.add((int) tmp); + + if (tmp == (int)tmp) { + result.add((int)tmp); } else { result.add(tmp); - } + } + break; case String: result.add(readableArray.getString(index)); @@ -142,7 +202,7 @@ public static List toList(@Nullable ReadableArray readableArray) { result = toList(readableArray.getArray(index)); break; default: - throw new IllegalArgumentException("Could not convert object with index: " + index + "."); + AdjustFactory.getLogger().error("Could not convert object with index: " + index + "."); } } @@ -159,79 +219,53 @@ public static boolean isFieldValid(String field) { return false; } - public static WritableMap attributionToMap(AdjustAttribution attribution) { - WritableMap map = Arguments.createMap(); - map.putString("trackerToken", attribution.trackerToken); - map.putString("trackerName", attribution.trackerName); - map.putString("network", attribution.network); - map.putString("campaign", attribution.campaign); - map.putString("adgroup", attribution.adgroup); - map.putString("creative", attribution.creative); - map.putString("clickLabel", attribution.clickLabel); - - return map; - } - - public static WritableMap eventSuccessToMap(AdjustEventSuccess eventSuccess) { - WritableMap map = Arguments.createMap(); - map.putString("message", eventSuccess.message); - map.putString("timestamp", eventSuccess.timestamp); - map.putString("adid", eventSuccess.adid); - map.putString("eventToken", eventSuccess.eventToken); - - if(eventSuccess.jsonResponse != null) { - map.putString("jsonResponse", eventSuccess.jsonResponse.toString()); - } - - return map; - } - - public static WritableMap eventFailureToMap(AdjustEventFailure eventFailure) { - WritableMap map = Arguments.createMap(); - map.putString("message", eventFailure.message); - map.putString("timestamp", eventFailure.timestamp); - map.putString("adid", eventFailure.adid); - map.putString("eventToken", eventFailure.eventToken); - map.putBoolean("willRetry", eventFailure.willRetry); - - if(eventFailure.jsonResponse != null) { - map.putString("jsonResponse", eventFailure.jsonResponse.toString()); - } - - return map; - } - - public static WritableMap sessionSuccessToMap(AdjustSessionSuccess sessionSuccess) { - WritableMap map = Arguments.createMap(); - map.putString("message", sessionSuccess.message); - map.putString("timestamp", sessionSuccess.timestamp); - map.putString("adid", sessionSuccess.adid); - - if(sessionSuccess.jsonResponse != null) { - map.putString("jsonResponse", sessionSuccess.jsonResponse.toString()); + /** + * toObject extracts a value from a {@link ReadableMap} by its key, + * and returns a POJO representing that object. + * + * @param readableMap The Map to containing the value to be converted + * @param key The key for the value to be converted + * @return The converted POJO + */ + private static Object toObject(@Nullable ReadableMap readableMap, String key) { + if (readableMap == null) { + return null; } - return map; - } + Object result = null; - public static WritableMap sessionFailureToMap(AdjustSessionFailure sessionFailure) { - WritableMap map = Arguments.createMap(); - map.putString("message", sessionFailure.message); - map.putString("timestamp", sessionFailure.timestamp); - map.putString("adid", sessionFailure.adid); - map.putBoolean("willRetry", sessionFailure.willRetry); + ReadableType readableType = readableMap.getType(key); + switch (readableType) { + case Null: + result = null; + break; + case Boolean: + result = readableMap.getBoolean(key); + break; + case Number: + // Can be int or double. + double tmp = readableMap.getDouble(key); + + if (tmp == (int)tmp) { + result = (int)tmp; + } else { + result = tmp; + } - if(sessionFailure.jsonResponse != null) { - map.putString("jsonResponse", sessionFailure.jsonResponse.toString()); + break; + case String: + result = readableMap.getString(key); + break; + case Map: + result = toMap(readableMap.getMap(key)); + break; + case Array: + result = toList(readableMap.getArray(key)); + break; + default: + AdjustFactory.getLogger().error("Could not convert object with key: " + key + "."); } - return map; - } - - public static WritableMap deferredDeeplinkToMap(Uri uri) { - WritableMap map = Arguments.createMap(); - map.putString("uri", uri.toString()); - - return map; + return result; } } diff --git a/sample/.babelrc b/example/.babelrc similarity index 100% rename from sample/.babelrc rename to example/.babelrc diff --git a/sample/.buckconfig b/example/.buckconfig similarity index 100% rename from sample/.buckconfig rename to example/.buckconfig diff --git a/sample/.flowconfig b/example/.flowconfig similarity index 100% rename from sample/.flowconfig rename to example/.flowconfig diff --git a/sample/.gitignore b/example/.gitignore similarity index 100% rename from sample/.gitignore rename to example/.gitignore diff --git a/sample/.watchmanconfig b/example/.watchmanconfig similarity index 100% rename from sample/.watchmanconfig rename to example/.watchmanconfig diff --git a/sample/index.android.js b/example/Screen1.js similarity index 59% rename from sample/index.android.js rename to example/Screen1.js index 470e31c8..0abda042 100644 --- a/sample/index.android.js +++ b/example/Screen1.js @@ -1,5 +1,5 @@ /** - * Sample React Native App + * Example React Native App * https://github.com/facebook/react-native * @flow */ @@ -12,12 +12,17 @@ import { Text, TouchableHighlight, View, - Linking + Linking, + Navigator } from 'react-native'; -export default class sample extends Component { +export default class Screen1 extends Component { componentDidMount() { - Linking.addEventListener('url', this.handleDeepLink); + const url = Linking.getInitialURL().then(url => { + if (url) { + Adjust.appWillOpenUrl(url); + } + }); } componentWillMount() { @@ -28,16 +33,21 @@ export default class sample extends Component { this._onPress_toggleOfflineMode = this._onPress_toggleOfflineMode.bind(this); this._onPress_toggleSdk = this._onPress_toggleSdk.bind(this); this._onPress_isSdkEnabled = this._onPress_isSdkEnabled.bind(this); + this._onPress_jumpToNextPage = this._onPress_jumpToNextPage.bind(this); this.isOffline = false; - var adjustConfig = new AdjustConfig("rb4g27fje5ej", AdjustConfig.EnvironmentSandbox); - + var adjustConfig = new AdjustConfig("2fm9gkqubvpc", AdjustConfig.EnvironmentSandbox); + adjustConfig.setLogLevel(AdjustConfig.LogLevelVerbose); + adjustConfig.setDelayStart(6.0); adjustConfig.setShouldLaunchDeeplink(true); - //adjustConfig.setEventBufferingEnabled(true); - // + adjustConfig.setSendInBackground(true); + + // adjustConfig.setEventBufferingEnabled(true); + // adjustConfig.setUserAgent("little_bunny_foo_foo"); + adjustConfig.setAttributionCallbackListener(function(attribution) { - console.log(">>> attribution callback received"); + console.log(">>> Attribution callback received"); console.log("Tracker token = " + attribution.trackerToken); console.log("Tracker name = " + attribution.trackerName); @@ -49,49 +59,49 @@ export default class sample extends Component { }); adjustConfig.setEventTrackingSucceededCallbackListener(function(eventSuccess) { - console.log(">>> event tracking succeeded callback received"); + console.log(">>> Event tracking succeeded callback received"); - console.log("message: " + eventSuccess.message); - console.log("timestamp: " + eventSuccess.timestamp); - console.log("adid: " + eventSuccess.adid); - console.log("eventToken: " + eventSuccess.eventToken); - console.log("json response: " + eventSuccess.jsonResponse ); + console.log("Message: " + eventSuccess.message); + console.log("Timestamp: " + eventSuccess.timestamp); + console.log("Adid: " + eventSuccess.adid); + console.log("Event token: " + eventSuccess.eventToken); + console.log("JSON response: " + eventSuccess.jsonResponse ); }); adjustConfig.setEventTrackingFailedCallbackListener(function(eventFailed) { - console.log(">>> event tracking failed callback received"); - - console.log("message: " + eventFailed.message); - console.log("timestamp: " + eventFailed.timestamp); - console.log("adid: " + eventFailed.adid); - console.log("eventToken: " + eventFailed.eventToken); - console.log("will retry: " + eventFailed.willRetry); - console.log("json response: " + eventFailed.jsonResponse); + console.log(">>> Event tracking failed callback received"); + + console.log("Message: " + eventFailed.message); + console.log("Timestamp: " + eventFailed.timestamp); + console.log("Adid: " + eventFailed.adid); + console.log("Event token: " + eventFailed.eventToken); + console.log("Will retry: " + eventFailed.willRetry); + console.log("JSON response: " + eventFailed.jsonResponse); }); adjustConfig.setSessionTrackingSucceededCallbackListener(function(sessionSuccess) { - console.log(">>> session tracking succeeded callback received"); + console.log(">>> Session tracking succeeded callback received"); - console.log("message: " + sessionSuccess.message); - console.log("timestamp: " + sessionSuccess.timestamp); - console.log("adid: " + sessionSuccess.adid); - console.log("json response: " + sessionSuccess.jsonResponse); + console.log("Message: " + sessionSuccess.message); + console.log("Timestamp: " + sessionSuccess.timestamp); + console.log("Adid: " + sessionSuccess.adid); + console.log("JSON response: " + sessionSuccess.jsonResponse); }); adjustConfig.setSessionTrackingFailedCallbackListener(function(sessionFailed) { - console.log(">>> session tracking failed callback received"); + console.log(">>> Session tracking failed callback received"); - console.log("message: " + sessionFailed.message); - console.log("timestamp: " + sessionFailed.timestamp); - console.log("adid: " + sessionFailed.adid); - console.log("will retry: " + sessionFailed.willRetry); - console.log("json response: " + sessionFailed.jsonResponse); + console.log("Message: " + sessionFailed.message); + console.log("Timestamp: " + sessionFailed.timestamp); + console.log("Adid: " + sessionFailed.adid); + console.log("Will retry: " + sessionFailed.willRetry); + console.log("JSON response: " + sessionFailed.jsonResponse); }); adjustConfig.setDeferredDeeplinkCallbackListener(function(uri) { console.log(">>> Deferred Deeplink Callback received"); - console.log("uri: " + uri.uri); + console.log("URL: " + uri.uri); }); Adjust.addSessionCallbackParameter("dummy_foo", "dummy_bar"); @@ -103,35 +113,21 @@ export default class sample extends Component { Adjust.removeSessionCallbackParameter("dummy_foo"); Adjust.removeSessionPartnerParameter("dummy_foo"); - //Adjust.resetSessionCallbackParameters(); - //Adjust.resetSessionPartnerParameters(); - - adjustConfig.setLogLevel(AdjustConfig.LogLevelVerbose); + // Adjust.resetSessionCallbackParameters(); + // Adjust.resetSessionPartnerParameters(); - adjustConfig.setDelayStart(3.0); - adjustConfig.setUserAgent("little_bunny_foo_foo"); + Adjust.setPushToken("bunny_foo_foo"); Adjust.create(adjustConfig); - Adjust.setPushToken("bunny_foo_foo"); - //Adjust.sendFirstPackages(); + Adjust.sendFirstPackages(); } componentWillUnmount() { - console.log(">>> componentWillUnmount"); - - Linking.removeEventListener('url', this.handleDeepLink); + console.log(">>> componentWillUnmount()") Adjust.componentWillUnmount(); } - handleDeepLink(e) { - const route = e.url.replace(/.*?:\/\//g, ""); - console.log("Received deeplink - url: " + e.url); - console.log("Received deeplink - route: " + route); - //this._navigator.replace(this.state.routes[route]); - Adjust.appWillOpenUrl(e.url); - } - render() { return ( @@ -180,105 +176,108 @@ export default class sample extends Component { onPress={this._onPress_isSdkEnabled}> is SDK Enabled? + + + Jump to Next Page + ); } _onPress_trackSimpleEvent() { - console.log(">> trackSimpleEvent()"); - - Adjust.isEnabled( (isEnabled) => { - if(isEnabled) { - var adjustEvent = new AdjustEvent("uqg17r"); + Adjust.isEnabled((isEnabled) => { + if (isEnabled) { + var adjustEvent = new AdjustEvent("g3mfiw"); Adjust.trackEvent(adjustEvent); } else { - console.log(">> SDK is disabled"); + console.log(">>> SDK is disabled"); } }); } _onPress_trackRevenueEvent() { - console.log(">> trackRevenueEvent()"); - - Adjust.isEnabled( (isEnabled) => { - if(isEnabled) { - var adjustEvent = new AdjustEvent("71iltz"); + Adjust.isEnabled((isEnabled) => { + if (isEnabled) { + var adjustEvent = new AdjustEvent("a4fd35"); adjustEvent.setRevenue(10.0, "USD"); Adjust.trackEvent(adjustEvent); } else { - console.log(">> SDK is disabled"); + console.log(">>> SDK is disabled"); } }); } _onPress_trackCallbackEvent() { - console.log(">> trackCallbackEvent()"); - - Adjust.isEnabled( (isEnabled) => { - if(isEnabled) { - var adjustEvent = new AdjustEvent("1ziip1"); + Adjust.isEnabled((isEnabled) => { + if (isEnabled) { + var adjustEvent = new AdjustEvent("34vgg9"); - adjustEvent.addCallbackParameters("DUMMY_KEY", "DUMMY_VALUE"); - adjustEvent.addCallbackParameters("DUMMY_KEY_2", "DUMMY_VALUE_2"); + adjustEvent.addCallbackParameter("DUMMY_KEY", "DUMMY_VALUE"); + adjustEvent.addCallbackParameter("DUMMY_KEY_2", "DUMMY_VALUE_2"); Adjust.trackEvent(adjustEvent); } else { - console.log(">> SDK is disabled"); + console.log(">>> SDK is disabled"); } }); } _onPress_trackPartnerEvent() { - console.log(">> trackPartnerEvent()"); + Adjust.isEnabled((isEnabled) => { + if (isEnabled) { + var adjustEvent = new AdjustEvent("w788qs"); - Adjust.isEnabled( (isEnabled) => { - if(isEnabled) { - var adjustEvent = new AdjustEvent("9s4lqn"); - - adjustEvent.addPartnerParameters("DUMMY_KEY", "DUMMY_VALUE"); - adjustEvent.addPartnerParameters("DUMMY_KEY_2", "DUMMY_VALUE_2"); + adjustEvent.addPartnerParameter("DUMMY_KEY", "DUMMY_VALUE"); + adjustEvent.addPartnerParameter("DUMMY_KEY_2", "DUMMY_VALUE_2"); Adjust.trackEvent(adjustEvent); } else { - console.log(">> SDK is disabled"); + console.log(">>> SDK is disabled"); } }); } _onPress_toggleOfflineMode() { - Adjust.isEnabled( (isEnabled) => { - if(isEnabled) { + Adjust.isEnabled((isEnabled) => { + if (isEnabled) { this.isOffline = !this.isOffline; - console.log(">> toggleOfflineMode(): SDK is " + this.isOffline); Adjust.setOfflineMode(this.isOffline); } else { - console.log(">> SDK is disabled"); + console.log(">>> SDK is disabled"); } }); } _onPress_toggleSdk() { Adjust.isEnabled( (isEnabled) => { - if(isEnabled) { - console.log(">> toggleSdk(): SDK Disabled"); + if (isEnabled) { Adjust.setEnabled(false); + console.log(">>> SDK disabled"); } else { - console.log(">> toggleSdk(): SDK Enabled"); Adjust.setEnabled(true); - Adjust.setOfflineMode(false); + console.log(">>> SDK enabled"); } }); } _onPress_isSdkEnabled() { Adjust.isEnabled( (isEnabled) => { - if(isEnabled) { - console.log(">> isSdkEnabled(): SDK is enabled"); + if (isEnabled) { + console.log(">>> SDK is enabled"); } else { - console.log(">> isSdkEnabled(): SDK is disabled"); + console.log(">>> SDK is disabled"); } }); } + + _onPress_jumpToNextPage() { + this.props.navigator.push({ + name: 'screen_2', + data: {} + }); + } } const styles = StyleSheet.create({ @@ -291,7 +290,7 @@ const styles = StyleSheet.create({ welcome: { fontSize: 20, textAlign: 'center', - margin: 10, + margin: 9, }, instructions: { textAlign: 'center', @@ -303,5 +302,3 @@ const styles = StyleSheet.create({ padding: 10 } }); - -AppRegistry.registerComponent('sample', () => sample); diff --git a/example/Screen2.js b/example/Screen2.js new file mode 100644 index 00000000..1e29442d --- /dev/null +++ b/example/Screen2.js @@ -0,0 +1,49 @@ +'use strict'; + +import React, { + Component +} from 'react'; + +import { + StyleSheet, + View, + Text, + TouchableHighlight, +} from 'react-native'; + +export default class Screen2 extends Component { + + constructor(props) { + super(props); + + this._onPress = this._onPress.bind(this); + } + + render() { + return ( + + This is Screen 2 + + Jump to screen 1 + + + ); + } + + _onPress() { + this.props.navigator.push({ + name: 'screen_1', + data: {} + }); + } +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + backgroundColor: 'teal' + }, +}); diff --git a/sample/__tests__/index.android.js b/example/__tests__/index.android.js similarity index 100% rename from sample/__tests__/index.android.js rename to example/__tests__/index.android.js diff --git a/sample/__tests__/index.ios.js b/example/__tests__/index.ios.js similarity index 100% rename from sample/__tests__/index.ios.js rename to example/__tests__/index.ios.js diff --git a/sample/android/app/BUCK b/example/android/app/BUCK similarity index 95% rename from sample/android/app/BUCK rename to example/android/app/BUCK index 2fb0cf1c..38a19280 100644 --- a/sample/android/app/BUCK +++ b/example/android/app/BUCK @@ -46,13 +46,13 @@ android_library( android_build_config( name = 'build_config', - package = 'com.adjust.example', + package = 'com.adjust.examples', ) android_resource( name = 'res', res = 'src/main/res', - package = 'com.adjust.example', + package = 'com.adjust.examples', ) android_binary( diff --git a/sample/android/app/build.gradle b/example/android/app/build.gradle similarity index 98% rename from sample/android/app/build.gradle rename to example/android/app/build.gradle index ce9fc854..18025230 100644 --- a/sample/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -87,7 +87,7 @@ android { buildToolsVersion "23.0.1" defaultConfig { - applicationId "com.adjust.example" + applicationId "com.adjust.examples" minSdkVersion 16 targetSdkVersion 22 versionCode 1 @@ -130,6 +130,7 @@ dependencies { compile fileTree(dir: "libs", include: ["*.jar"]) compile "com.android.support:appcompat-v7:23.0.1" compile "com.facebook.react:react-native:+" // From node_modules + compile 'com.google.android.gms:play-services-analytics:+' } // Run this once to be able to run the application with BUCK diff --git a/sample/android/app/proguard-rules.pro b/example/android/app/proguard-rules.pro similarity index 100% rename from sample/android/app/proguard-rules.pro rename to example/android/app/proguard-rules.pro diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..9f2efdc4 --- /dev/null +++ b/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sample/android/app/src/main/java/com/adjust/example/MainActivity.java b/example/android/app/src/main/java/com/adjust/example/MainActivity.java similarity index 85% rename from sample/android/app/src/main/java/com/adjust/example/MainActivity.java rename to example/android/app/src/main/java/com/adjust/example/MainActivity.java index a9085670..71545785 100644 --- a/sample/android/app/src/main/java/com/adjust/example/MainActivity.java +++ b/example/android/app/src/main/java/com/adjust/example/MainActivity.java @@ -1,4 +1,4 @@ -package com.adjust.example; +package com.adjust.examples; import com.facebook.react.ReactActivity; @@ -10,6 +10,6 @@ public class MainActivity extends ReactActivity { */ @Override protected String getMainComponentName() { - return "sample"; + return "Example"; } } diff --git a/sample/android/app/src/main/java/com/adjust/example/MainApplication.java b/example/android/app/src/main/java/com/adjust/example/MainApplication.java similarity index 96% rename from sample/android/app/src/main/java/com/adjust/example/MainApplication.java rename to example/android/app/src/main/java/com/adjust/example/MainApplication.java index d93de27b..eeaa1526 100644 --- a/sample/android/app/src/main/java/com/adjust/example/MainApplication.java +++ b/example/android/app/src/main/java/com/adjust/example/MainApplication.java @@ -1,4 +1,4 @@ -package com.adjust.example; +package com.adjust.examples; import android.app.Application; import android.util.Log; diff --git a/sample/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from sample/android/app/src/main/res/mipmap-hdpi/ic_launcher.png rename to example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/sample/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from sample/android/app/src/main/res/mipmap-mdpi/ic_launcher.png rename to example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/sample/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from sample/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png rename to example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/sample/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from sample/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/example/android/app/src/main/res/values/strings.xml b/example/android/app/src/main/res/values/strings.xml new file mode 100644 index 00000000..0057fcb9 --- /dev/null +++ b/example/android/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + Example + diff --git a/sample/android/app/src/main/res/values/styles.xml b/example/android/app/src/main/res/values/styles.xml similarity index 100% rename from sample/android/app/src/main/res/values/styles.xml rename to example/android/app/src/main/res/values/styles.xml diff --git a/sample/android/build.gradle b/example/android/build.gradle similarity index 100% rename from sample/android/build.gradle rename to example/android/build.gradle diff --git a/sample/android/gradle.properties b/example/android/gradle.properties similarity index 100% rename from sample/android/gradle.properties rename to example/android/gradle.properties diff --git a/sample/android/gradle/wrapper/gradle-wrapper.jar b/example/android/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from sample/android/gradle/wrapper/gradle-wrapper.jar rename to example/android/gradle/wrapper/gradle-wrapper.jar diff --git a/sample/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from sample/android/gradle/wrapper/gradle-wrapper.properties rename to example/android/gradle/wrapper/gradle-wrapper.properties diff --git a/sample/android/gradlew b/example/android/gradlew similarity index 100% rename from sample/android/gradlew rename to example/android/gradlew diff --git a/sample/android/gradlew.bat b/example/android/gradlew.bat similarity index 100% rename from sample/android/gradlew.bat rename to example/android/gradlew.bat diff --git a/sample/android/keystores/BUCK b/example/android/keystores/BUCK similarity index 100% rename from sample/android/keystores/BUCK rename to example/android/keystores/BUCK diff --git a/sample/android/keystores/debug.keystore.properties b/example/android/keystores/debug.keystore.properties similarity index 100% rename from sample/android/keystores/debug.keystore.properties rename to example/android/keystores/debug.keystore.properties diff --git a/sample/android/settings.gradle b/example/android/settings.gradle similarity index 85% rename from sample/android/settings.gradle rename to example/android/settings.gradle index 36e6fad6..5db941bf 100644 --- a/sample/android/settings.gradle +++ b/example/android/settings.gradle @@ -1,4 +1,4 @@ -rootProject.name = 'sample' +rootProject.name = 'Example' include ':app' include ':react-native-adjust' diff --git a/example/index.android.js b/example/index.android.js new file mode 100644 index 00000000..f5fb77dd --- /dev/null +++ b/example/index.android.js @@ -0,0 +1,45 @@ +'use strict'; + +import React, { Component } from 'react'; +import { + AppRegistry, + StyleSheet, + Text, + View, + Navigator, + TouchableHighlight +} from 'react-native'; + +import Screen1 from './Screen1'; +import Screen2 from './Screen2'; + +class Example extends Component { + + _renderScene(route, navigator) { + switch (route.name) { + case 'screen_1': + return ; + case 'screen_2': + return ; + default: + console.error('Encountered unexpected route: ' + route.name); + } + + return ; + } + + render() { + return ( + + ); + } +} + +const styles = StyleSheet.create({ +}); + +AppRegistry.registerComponent('Example', () => Example); diff --git a/sample/index.ios.js b/example/index.ios.js similarity index 61% rename from sample/index.ios.js rename to example/index.ios.js index 875c55a9..5149a014 100644 --- a/sample/index.ios.js +++ b/example/index.ios.js @@ -1,5 +1,6 @@ + /** - * Sample React Native App + * Example React Native App * https://github.com/facebook/react-native * @flow */ @@ -15,7 +16,7 @@ import { Linking } from 'react-native'; -export default class sample extends Component { +export default class Example extends Component { componentDidMount() { Linking.addEventListener('url', this.handleDeepLink); } @@ -31,10 +32,17 @@ export default class sample extends Component { this.isOffline = false; - var adjustConfig = new AdjustConfig("rb4g27fje5ej", AdjustConfig.EnvironmentSandbox); + var adjustConfig = new AdjustConfig("2fm9gkqubvpc", AdjustConfig.EnvironmentSandbox); + adjustConfig.setLogLevel(AdjustConfig.LogLevelVerbose); + adjustConfig.setDelayStart(6.0); + adjustConfig.setShouldLaunchDeeplink(true); + adjustConfig.setSendInBackground(true); + + // adjustConfig.setEventBufferingEnabled(true); + // adjustConfig.setUserAgent("little_bunny_foo_foo"); adjustConfig.setAttributionCallbackListener(function(attribution) { - console.log(">>> attribution callback received"); + console.log(">>> Attribution callback received"); console.log("Tracker token = " + attribution.trackerToken); console.log("Tracker name = " + attribution.trackerName); @@ -46,54 +54,51 @@ export default class sample extends Component { }); adjustConfig.setEventTrackingSucceededCallbackListener(function(eventSuccess) { - console.log(">>> event tracking succeeded callback received"); + console.log(">>> Event tracking succeeded callback received"); - console.log("message: " + eventSuccess.message); - console.log("timeStamp: " + eventSuccess.timeStamp); - console.log("adid: " + eventSuccess.adid); - console.log("eventToken: " + eventSuccess.eventToken); - console.log("json response: " + eventSuccess.jsonResponse ); + console.log("Message: " + eventSuccess.message); + console.log("Timestamp: " + eventSuccess.timestamp); + console.log("Adid: " + eventSuccess.adid); + console.log("Event token: " + eventSuccess.eventToken); + console.log("JSON response: " + eventSuccess.jsonResponse ); }); adjustConfig.setEventTrackingFailedCallbackListener(function(eventFailed) { - console.log(">>> event tracking failed callback received"); - - console.log("message: " + eventFailed.message); - console.log("timeStamp: " + eventFailed.timeStamp); - console.log("adid: " + eventFailed.adid); - console.log("eventToken: " + eventFailed.eventToken); - console.log("will retry: " + eventFailed.willRetry); - console.log("json response: " + eventFailed.jsonResponse); + console.log(">>> Event tracking failed callback received"); + + console.log("Message: " + eventFailed.message); + console.log("Timestamp: " + eventFailed.timestamp); + console.log("Adid: " + eventFailed.adid); + console.log("Event token: " + eventFailed.eventToken); + console.log("Will retry: " + eventFailed.willRetry); + console.log("JSON response: " + eventFailed.jsonResponse); }); adjustConfig.setSessionTrackingSucceededCallbackListener(function(sessionSuccess) { - console.log(">>> session tracking succeeded callback received"); + console.log(">>> Session tracking succeeded callback received"); - console.log("message: " + sessionSuccess.message); - console.log("timeStamp: " + sessionSuccess.timeStamp); - console.log("adid: " + sessionSuccess.adid); - console.log("json response: " + sessionSuccess.jsonResponse); + console.log("Message: " + sessionSuccess.message); + console.log("Timestamp: " + sessionSuccess.timestamp); + console.log("Adid: " + sessionSuccess.adid); + console.log("JSON response: " + sessionSuccess.jsonResponse); }); adjustConfig.setSessionTrackingFailedCallbackListener(function(sessionFailed) { - console.log(">>> session tracking failed callback received"); + console.log(">>> Session tracking failed callback received"); - console.log("message: " + sessionFailed.message); - console.log("timeStamp: " + sessionFailed.timeStamp); - console.log("adid: " + sessionFailed.adid); - console.log("will retry: " + sessionFailed.willRetry); - console.log("json response: " + sessionFailed.jsonResponse); + console.log("Message: " + sessionFailed.message); + console.log("Timestamp: " + sessionFailed.timestamp); + console.log("Adid: " + sessionFailed.adid); + console.log("Will retry: " + sessionFailed.willRetry); + console.log("JSON response: " + sessionFailed.jsonResponse); }); adjustConfig.setDeferredDeeplinkCallbackListener(function(uri) { console.log(">>> Deferred Deeplink Callback received"); - console.log("uri: " + uri.uri); + console.log("URL: " + uri.uri); }); - adjustConfig.setShouldLaunchDeeplink(true); - //adjustConfig.setEventBufferingEnabled(true); - Adjust.addSessionCallbackParameter("dummy_foo", "dummy_bar"); Adjust.addSessionCallbackParameter("dummy_foo_foo", "dummy_bar"); @@ -103,14 +108,10 @@ export default class sample extends Component { Adjust.removeSessionCallbackParameter("dummy_foo"); Adjust.removeSessionPartnerParameter("dummy_foo"); - Adjust.resetSessionCallbackParameters(); - Adjust.resetSessionPartnerParameters(); - Adjust.setPushToken("bunny_foo_foo"); - - adjustConfig.setLogLevel(AdjustConfig.LogLevelVerbose); + // Adjust.resetSessionCallbackParameters(); + // Adjust.resetSessionPartnerParameters(); - adjustConfig.setDelayStart(3.0); - adjustConfig.setUserAgent("little_bunny_foo_foo"); + Adjust.setPushToken("bunny_foo_foo"); Adjust.create(adjustConfig); @@ -118,17 +119,10 @@ export default class sample extends Component { } componentWillUnmount() { - console.log(">>> componentWillUnmount"); - Linking.removeEventListener('url', this.handleDeepLink); - Adjust.componentWillUnmount(); } handleDeepLink(e) { - const route = e.url.replace(/.*?:\/\//g, ""); - console.log("Received deeplink - url: " + e.url); - console.log("Received deeplink - route: " + route); - //this._navigator.replace(this.state.routes[route]); Adjust.appWillOpenUrl(e.url); } @@ -185,88 +179,77 @@ export default class sample extends Component { } _onPress_trackSimpleEvent() { - console.log(">> trackSimpleEvent()"); - - Adjust.isEnabled( (isEnabled) => { - if(isEnabled) { - var adjustEvent = new AdjustEvent("uqg17r"); - + Adjust.isEnabled((isEnabled) => { + if (isEnabled) { + var adjustEvent = new AdjustEvent("g3mfiw"); Adjust.trackEvent(adjustEvent); } else { - console.log(">> SDK is disabled"); + console.log(">>> SDK is disabled"); } }); } _onPress_trackRevenueEvent() { - console.log(">> trackRevenueEvent()"); - - Adjust.isEnabled( (isEnabled) => { - if(isEnabled) { - var adjustEvent = new AdjustEvent("71iltz"); + Adjust.isEnabled((isEnabled) => { + if (isEnabled) { + var adjustEvent = new AdjustEvent("a4fd35"); adjustEvent.setRevenue(10.0, "USD"); Adjust.trackEvent(adjustEvent); } else { - console.log(">> SDK is disabled"); + console.log(">>> SDK is disabled"); } }); } _onPress_trackCallbackEvent() { - console.log(">> trackCallbackEvent()"); - - Adjust.isEnabled( (isEnabled) => { - if(isEnabled) { - var adjustEvent = new AdjustEvent("1ziip1"); + Adjust.isEnabled((isEnabled) => { + if (isEnabled) { + var adjustEvent = new AdjustEvent("34vgg9"); - adjustEvent.addCallbackParameters("DUMMY_KEY", "DUMMY_VALUE"); - adjustEvent.addCallbackParameters("DUMMY_KEY_2", "DUMMY_VALUE_2"); + adjustEvent.addCallbackParameter("DUMMY_KEY", "DUMMY_VALUE"); + adjustEvent.addCallbackParameter("DUMMY_KEY_2", "DUMMY_VALUE_2"); Adjust.trackEvent(adjustEvent); } else { - console.log(">> SDK is disabled"); + console.log(">>> SDK is disabled"); } }); } _onPress_trackPartnerEvent() { - console.log(">> trackPartnerEvent()"); + Adjust.isEnabled((isEnabled) => { + if (isEnabled) { + var adjustEvent = new AdjustEvent("w788qs"); - Adjust.isEnabled( (isEnabled) => { - if(isEnabled) { - var adjustEvent = new AdjustEvent("9s4lqn"); - - adjustEvent.addPartnerParameters("DUMMY_KEY", "DUMMY_VALUE"); - adjustEvent.addPartnerParameters("DUMMY_KEY_2", "DUMMY_VALUE_2"); + adjustEvent.addPartnerParameter("DUMMY_KEY", "DUMMY_VALUE"); + adjustEvent.addPartnerParameter("DUMMY_KEY_2", "DUMMY_VALUE_2"); Adjust.trackEvent(adjustEvent); } else { - console.log(">> SDK is disabled"); + console.log(">>> SDK is disabled"); } }); } _onPress_toggleOfflineMode() { - Adjust.isEnabled( (isEnabled) => { - if(isEnabled) { + Adjust.isEnabled((isEnabled) => { + if (isEnabled) { this.isOffline = !this.isOffline; - console.log(">> toggleOfflineMode(): SDK is " + this.isOffline); Adjust.setOfflineMode(this.isOffline); } else { - console.log(">> SDK is disabled"); + console.log(">>> SDK is disabled"); } }); } _onPress_toggleSdk() { Adjust.isEnabled( (isEnabled) => { - if(isEnabled) { - console.log(">> toggleSdk(): SDK Disabled"); + if (isEnabled) { Adjust.setEnabled(false); + console.log(">>> SDK disabled"); } else { - console.log(">> toggleSdk(): SDK Enabled"); Adjust.setEnabled(true); - Adjust.setOfflineMode(false); + console.log(">>> SDK enabled"); } }); } @@ -274,9 +257,9 @@ export default class sample extends Component { _onPress_isSdkEnabled() { Adjust.isEnabled( (isEnabled) => { if(isEnabled) { - console.log(">> isSdkEnabled(): SDK is enabled"); + console.log(">>> SDK is enabled"); } else { - console.log(">> isSdkEnabled(): SDK is disabled"); + console.log(">>> SDK is disabled"); } }); } @@ -305,4 +288,4 @@ const styles = StyleSheet.create({ } }); -AppRegistry.registerComponent('sample', () => sample); +AppRegistry.registerComponent('Example', () => Example); diff --git a/sample/ios/sample.xcodeproj/project.pbxproj b/example/ios/Example.xcodeproj/project.pbxproj similarity index 86% rename from sample/ios/sample.xcodeproj/project.pbxproj rename to example/ios/Example.xcodeproj/project.pbxproj index 19027cb4..88940488 100644 --- a/sample/ios/sample.xcodeproj/project.pbxproj +++ b/example/ios/Example.xcodeproj/project.pbxproj @@ -12,7 +12,7 @@ 00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */; }; 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */; }; 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */; }; - 00E356F31AD99517003FC87E /* sampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* sampleTests.m */; }; + 00E356F31AD99517003FC87E /* ExampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* ExampleTests.m */; }; 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78C398B91ACF4ADC00677621 /* libRCTLinking.a */; }; 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */; }; 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */; }; @@ -23,7 +23,9 @@ 140ED2AC1D01E1AD002B40FF /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; }; 146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; }; 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; }; - D30926E85410447D8569BC75 /* libadjustSdk.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DA5DA7F2FB04554AC598BF8 /* libadjustSdk.a */; }; + 9D6A23711DE85054002D401C /* AdSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9D6A23701DE85054002D401C /* AdSupport.framework */; }; + 9D6A23731DE8505B002D401C /* iAd.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9D6A23721DE8505B002D401C /* iAd.framework */; }; + D30926E85410447D8569BC75 /* libAdjustSdk.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DA5DA7F2FB04554AC598BF8 /* libAdjustSdk.a */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -67,7 +69,7 @@ containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */; proxyType = 1; remoteGlobalIDString = 13B07F861A680F5B00A75B9A; - remoteInfo = sample; + remoteInfo = Example; }; 139105C01AF99BAD00B5F7CC /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; @@ -92,10 +94,10 @@ }; 20A410951DDF4452003ED776 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; - containerPortal = 4934B58D37FA4780895400B4 /* adjustSdk.xcodeproj */; + containerPortal = 4934B58D37FA4780895400B4 /* AdjustSdk.xcodeproj */; proxyType = 2; remoteGlobalIDString = 134814201AA4EA6300B7C361; - remoteInfo = adjustSdk; + remoteInfo = AdjustSdk; }; 20A4109B1DDF4452003ED776 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; @@ -169,23 +171,26 @@ 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = "../node_modules/react-native/Libraries/Image/RCTImage.xcodeproj"; sourceTree = ""; }; 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = "../node_modules/react-native/Libraries/Network/RCTNetwork.xcodeproj"; sourceTree = ""; }; 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = "../node_modules/react-native/Libraries/Vibration/RCTVibration.xcodeproj"; sourceTree = ""; }; - 00E356EE1AD99517003FC87E /* sampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = sampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 00E356EE1AD99517003FC87E /* ExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 00E356F21AD99517003FC87E /* sampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = sampleTests.m; sourceTree = ""; }; + 00E356F21AD99517003FC87E /* ExampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ExampleTests.m; sourceTree = ""; }; 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = "../node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj"; sourceTree = ""; }; 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = "../node_modules/react-native/Libraries/WebSocket/RCTWebSocket.xcodeproj"; sourceTree = ""; }; - 13B07F961A680F5B00A75B9A /* sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = sample.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = sample/AppDelegate.h; sourceTree = ""; }; - 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = sample/AppDelegate.m; sourceTree = ""; }; + 13B07F961A680F5B00A75B9A /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = Example/AppDelegate.h; sourceTree = ""; }; + 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = Example/AppDelegate.m; sourceTree = ""; }; 13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; - 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = sample/Images.xcassets; sourceTree = ""; }; - 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = sample/Info.plist; sourceTree = ""; }; - 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = sample/main.m; sourceTree = ""; }; + 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = Example/Images.xcassets; sourceTree = ""; }; + 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Example/Info.plist; sourceTree = ""; }; + 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = Example/main.m; sourceTree = ""; }; 146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = ""; }; - 4934B58D37FA4780895400B4 /* adjustSdk.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = adjustSdk.xcodeproj; path = "../node_modules/react-native-adjust/ios/adjustSdk.xcodeproj"; sourceTree = ""; }; + 4934B58D37FA4780895400B4 /* AdjustSdk.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = AdjustSdk.xcodeproj; path = "../node_modules/react-native-adjust/ios/AdjustSdk.xcodeproj"; sourceTree = ""; }; 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = ""; }; 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = ""; }; - 8DA5DA7F2FB04554AC598BF8 /* libadjustSdk.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libadjustSdk.a; sourceTree = ""; }; + 8DA5DA7F2FB04554AC598BF8 /* libAdjustSdk.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libAdjustSdk.a; sourceTree = ""; }; + 9D6A23701DE85054002D401C /* AdSupport.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AdSupport.framework; path = System/Library/Frameworks/AdSupport.framework; sourceTree = SDKROOT; }; + 9D6A23721DE8505B002D401C /* iAd.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = iAd.framework; path = System/Library/Frameworks/iAd.framework; sourceTree = SDKROOT; }; + 9DB5EAF81DE7333F00A5177D /* Example.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = Example.entitlements; path = Example/Example.entitlements; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -201,6 +206,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 9D6A23731DE8505B002D401C /* iAd.framework in Frameworks */, + 9D6A23711DE85054002D401C /* AdSupport.framework in Frameworks */, 146834051AC3E58100842450 /* libReact.a in Frameworks */, 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */, 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */, @@ -211,7 +218,7 @@ 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */, 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */, 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */, - D30926E85410447D8569BC75 /* libadjustSdk.a in Frameworks */, + D30926E85410447D8569BC75 /* libAdjustSdk.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -260,13 +267,13 @@ name = Products; sourceTree = ""; }; - 00E356EF1AD99517003FC87E /* sampleTests */ = { + 00E356EF1AD99517003FC87E /* ExampleTests */ = { isa = PBXGroup; children = ( - 00E356F21AD99517003FC87E /* sampleTests.m */, + 00E356F21AD99517003FC87E /* ExampleTests.m */, 00E356F01AD99517003FC87E /* Supporting Files */, ); - path = sampleTests; + path = ExampleTests; sourceTree = ""; }; 00E356F01AD99517003FC87E /* Supporting Files */ = { @@ -295,9 +302,10 @@ name = Products; sourceTree = ""; }; - 13B07FAE1A68108700A75B9A /* sample */ = { + 13B07FAE1A68108700A75B9A /* Example */ = { isa = PBXGroup; children = ( + 9DB5EAF81DE7333F00A5177D /* Example.entitlements */, 008F07F21AC5B25A0029DE68 /* main.jsbundle */, 13B07FAF1A68108700A75B9A /* AppDelegate.h */, 13B07FB01A68108700A75B9A /* AppDelegate.m */, @@ -306,7 +314,7 @@ 13B07FB11A68108700A75B9A /* LaunchScreen.xib */, 13B07FB71A68108700A75B9A /* main.m */, ); - name = sample; + name = Example; sourceTree = ""; }; 146834001AC3E56700842450 /* Products */ = { @@ -321,7 +329,7 @@ 20A410921DDF4452003ED776 /* Products */ = { isa = PBXGroup; children = ( - 20A410961DDF4452003ED776 /* libadjustSdk.a */, + 20A410961DDF4452003ED776 /* libAdjustSdk.a */, ); name = Products; sourceTree = ""; @@ -348,7 +356,7 @@ 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */, 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */, 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */, - 4934B58D37FA4780895400B4 /* adjustSdk.xcodeproj */, + 4934B58D37FA4780895400B4 /* AdjustSdk.xcodeproj */, ); name = Libraries; sourceTree = ""; @@ -365,10 +373,11 @@ 83CBB9F61A601CBA00E9B192 = { isa = PBXGroup; children = ( - 13B07FAE1A68108700A75B9A /* sample */, + 13B07FAE1A68108700A75B9A /* Example */, 832341AE1AAA6A7D00B99B32 /* Libraries */, - 00E356EF1AD99517003FC87E /* sampleTests */, + 00E356EF1AD99517003FC87E /* ExampleTests */, 83CBBA001A601CBA00E9B192 /* Products */, + 9D6A23551DE84B59002D401C /* Frameworks */, ); indentWidth = 2; sourceTree = ""; @@ -377,18 +386,27 @@ 83CBBA001A601CBA00E9B192 /* Products */ = { isa = PBXGroup; children = ( - 13B07F961A680F5B00A75B9A /* sample.app */, - 00E356EE1AD99517003FC87E /* sampleTests.xctest */, + 13B07F961A680F5B00A75B9A /* Example.app */, + 00E356EE1AD99517003FC87E /* ExampleTests.xctest */, ); name = Products; sourceTree = ""; }; + 9D6A23551DE84B59002D401C /* Frameworks */ = { + isa = PBXGroup; + children = ( + 9D6A23721DE8505B002D401C /* iAd.framework */, + 9D6A23701DE85054002D401C /* AdSupport.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 00E356ED1AD99517003FC87E /* sampleTests */ = { + 00E356ED1AD99517003FC87E /* ExampleTests */ = { isa = PBXNativeTarget; - buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "sampleTests" */; + buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "ExampleTests" */; buildPhases = ( 00E356EA1AD99517003FC87E /* Sources */, 00E356EB1AD99517003FC87E /* Frameworks */, @@ -399,14 +417,14 @@ dependencies = ( 00E356F51AD99517003FC87E /* PBXTargetDependency */, ); - name = sampleTests; - productName = sampleTests; - productReference = 00E356EE1AD99517003FC87E /* sampleTests.xctest */; + name = ExampleTests; + productName = ExampleTests; + productReference = 00E356EE1AD99517003FC87E /* ExampleTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; - 13B07F861A680F5B00A75B9A /* sample */ = { + 13B07F861A680F5B00A75B9A /* Example */ = { isa = PBXNativeTarget; - buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "sample" */; + buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "Example" */; buildPhases = ( 13B07F871A680F5B00A75B9A /* Sources */, 13B07F8C1A680F5B00A75B9A /* Frameworks */, @@ -417,9 +435,9 @@ ); dependencies = ( ); - name = sample; + name = Example; productName = "Hello World"; - productReference = 13B07F961A680F5B00A75B9A /* sample.app */; + productReference = 13B07F961A680F5B00A75B9A /* Example.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ @@ -433,11 +451,20 @@ TargetAttributes = { 00E356ED1AD99517003FC87E = { CreatedOnToolsVersion = 6.2; + DevelopmentTeam = QGUGW9AUMK; TestTargetID = 13B07F861A680F5B00A75B9A; }; + 13B07F861A680F5B00A75B9A = { + DevelopmentTeam = QGUGW9AUMK; + SystemCapabilities = { + com.apple.SafariKeychain = { + enabled = 1; + }; + }; + }; }; }; - buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "sample" */; + buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "Example" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; @@ -451,7 +478,7 @@ projectReferences = ( { ProductGroup = 20A410921DDF4452003ED776 /* Products */; - ProjectRef = 4934B58D37FA4780895400B4 /* adjustSdk.xcodeproj */; + ProjectRef = 4934B58D37FA4780895400B4 /* AdjustSdk.xcodeproj */; }, { ProductGroup = 00C302A81ABCB8CE00DB3ED1 /* Products */; @@ -496,8 +523,8 @@ ); projectRoot = ""; targets = ( - 13B07F861A680F5B00A75B9A /* sample */, - 00E356ED1AD99517003FC87E /* sampleTests */, + 13B07F861A680F5B00A75B9A /* Example */, + 00E356ED1AD99517003FC87E /* ExampleTests */, ); }; /* End PBXProject section */ @@ -559,10 +586,10 @@ remoteRef = 146834031AC3E56700842450 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 20A410961DDF4452003ED776 /* libadjustSdk.a */ = { + 20A410961DDF4452003ED776 /* libAdjustSdk.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; - path = libadjustSdk.a; + path = libAdjustSdk.a; remoteRef = 20A410951DDF4452003ED776 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -672,7 +699,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 00E356F31AD99517003FC87E /* sampleTests.m in Sources */, + 00E356F31AD99517003FC87E /* ExampleTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -690,7 +717,7 @@ /* Begin PBXTargetDependency section */ 00E356F51AD99517003FC87E /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 13B07F861A680F5B00A75B9A /* sample */; + target = 13B07F861A680F5B00A75B9A /* Example */; targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ @@ -702,7 +729,7 @@ 13B07FB21A68108700A75B9A /* Base */, ); name = LaunchScreen.xib; - path = sample; + path = Example; sourceTree = ""; }; /* End PBXVariantGroup section */ @@ -712,11 +739,12 @@ isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; + DEVELOPMENT_TEAM = QGUGW9AUMK; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); - INFOPLIST_FILE = sampleTests/Info.plist; + INFOPLIST_FILE = ExampleTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( @@ -724,7 +752,7 @@ "\"$(SRCROOT)/$(TARGET_NAME)\"", ); PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/sample.app/sample"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Example.app/Example"; }; name = Debug; }; @@ -733,7 +761,8 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; COPY_PHASE_STRIP = NO; - INFOPLIST_FILE = sampleTests/Info.plist; + DEVELOPMENT_TEAM = QGUGW9AUMK; + INFOPLIST_FILE = ExampleTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( @@ -741,7 +770,7 @@ "\"$(SRCROOT)/$(TARGET_NAME)\"", ); PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/sample.app/sample"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Example.app/Example"; }; name = Release; }; @@ -749,22 +778,25 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = Example/Example.entitlements; CURRENT_PROJECT_VERSION = 1; DEAD_CODE_STRIPPING = NO; + DEVELOPMENT_TEAM = QGUGW9AUMK; HEADER_SEARCH_PATHS = ( "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, "$(SRCROOT)/../node_modules/react-native/React/**", "$(SRCROOT)/../node_modules/react-native-adjust/ios/**", ); - INFOPLIST_FILE = sample/Info.plist; + INFOPLIST_FILE = Example/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", "-lc++", ); - PRODUCT_NAME = sample; + PRODUCT_BUNDLE_IDENTIFIER = com.adjust.examples; + PRODUCT_NAME = Example; VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; @@ -773,21 +805,24 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = Example/Example.entitlements; CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = QGUGW9AUMK; HEADER_SEARCH_PATHS = ( "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, "$(SRCROOT)/../node_modules/react-native/React/**", "$(SRCROOT)/../node_modules/react-native-adjust/ios/**", ); - INFOPLIST_FILE = sample/Info.plist; + INFOPLIST_FILE = Example/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", "-lc++", ); - PRODUCT_NAME = sample; + PRODUCT_BUNDLE_IDENTIFIER = com.adjust.examples; + PRODUCT_NAME = Example; VERSIONING_SYSTEM = "apple-generic"; }; name = Release; @@ -883,7 +918,7 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "sampleTests" */ = { + 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "ExampleTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 00E356F61AD99517003FC87E /* Debug */, @@ -892,7 +927,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "sample" */ = { + 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "Example" */ = { isa = XCConfigurationList; buildConfigurations = ( 13B07F941A680F5B00A75B9A /* Debug */, @@ -901,7 +936,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "sample" */ = { + 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "Example" */ = { isa = XCConfigurationList; buildConfigurations = ( 83CBBA201A601CBA00E9B192 /* Debug */, diff --git a/sample/ios/sample.xcodeproj/xcshareddata/xcschemes/sample.xcscheme b/example/ios/Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme similarity index 78% rename from sample/ios/sample.xcodeproj/xcshareddata/xcschemes/sample.xcscheme rename to example/ios/Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme index c6d9e688..abcf8a65 100644 --- a/sample/ios/sample.xcodeproj/xcshareddata/xcschemes/sample.xcscheme +++ b/example/ios/Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme @@ -15,9 +15,9 @@ + BuildableName = "Example.app" + BlueprintName = "Example" + ReferencedContainer = "container:Example.xcodeproj"> + BuildableName = "ExampleTests.xctest" + BlueprintName = "ExampleTests" + ReferencedContainer = "container:Example.xcodeproj"> @@ -47,9 +47,9 @@ + BuildableName = "ExampleTests.xctest" + BlueprintName = "ExampleTests" + ReferencedContainer = "container:Example.xcodeproj"> @@ -57,9 +57,9 @@ + BuildableName = "Example.app" + BlueprintName = "Example" + ReferencedContainer = "container:Example.xcodeproj"> @@ -77,9 +77,9 @@ + BuildableName = "Example.app" + BlueprintName = "Example" + ReferencedContainer = "container:Example.xcodeproj"> @@ -96,9 +96,9 @@ + BuildableName = "Example.app" + BlueprintName = "Example" + ReferencedContainer = "container:Example.xcodeproj"> diff --git a/sample/ios/sample/AppDelegate.h b/example/ios/Example/AppDelegate.h similarity index 100% rename from sample/ios/sample/AppDelegate.h rename to example/ios/Example/AppDelegate.h diff --git a/sample/ios/sample/AppDelegate.m b/example/ios/Example/AppDelegate.m similarity index 60% rename from sample/ios/sample/AppDelegate.m rename to example/ios/Example/AppDelegate.m index f62f257f..840bca00 100644 --- a/sample/ios/sample/AppDelegate.m +++ b/example/ios/Example/AppDelegate.m @@ -9,28 +9,49 @@ #import "AppDelegate.h" -#import "RCTBundleURLProvider.h" +#import "Adjust.h" #import "RCTRootView.h" +#import "RCTBundleURLProvider.h" @implementation AppDelegate -- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions -{ +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { NSURL *jsCodeLocation; - + jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil]; - RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation - moduleName:@"sample" + moduleName:@"Example" initialProperties:nil launchOptions:launchOptions]; + rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; - self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; + UIViewController *rootViewController = [UIViewController new]; rootViewController.view = rootView; + self.window.rootViewController = rootViewController; [self.window makeKeyAndVisible]; + + return YES; +} + +- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation { + NSLog(@"openURL method called with URL: %@", url); + + [Adjust appWillOpenUrl:url]; + + return YES; +} + +- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray *restorableObjects))restorationHandler { + if ([[userActivity activityType] isEqualToString:NSUserActivityTypeBrowsingWeb]) { + NSLog(@"continueUserActivity method called with URL: %@", [userActivity webpageURL]); + + [Adjust convertUniversalLink:[userActivity webpageURL] scheme:@"adjustExample"]; + [Adjust appWillOpenUrl:[userActivity webpageURL]]; + } + return YES; } diff --git a/sample/ios/sample/Base.lproj/LaunchScreen.xib b/example/ios/Example/Base.lproj/LaunchScreen.xib similarity index 93% rename from sample/ios/sample/Base.lproj/LaunchScreen.xib rename to example/ios/Example/Base.lproj/LaunchScreen.xib index 1f9ab651..8c70b043 100644 --- a/sample/ios/sample/Base.lproj/LaunchScreen.xib +++ b/example/ios/Example/Base.lproj/LaunchScreen.xib @@ -18,7 +18,7 @@ -