From 77a75b2afe5ae0fdf8ea834be1a3db3750101e19 Mon Sep 17 00:00:00 2001 From: Karen Tamayo Date: Tue, 4 Jun 2024 11:37:25 -0700 Subject: [PATCH] [MT-1507] InstallReferrer, AdIdentifier, and Attribution Module (#173) Support for InstallReferrer (Android), AdIdentifier (Android), and Attribution (iOS) Module --- example/App.js | 15 ++- .../android/app/src/debug/AndroidManifest.xml | 4 +- .../android/app/src/main/AndroidManifest.xml | 6 +- example/ios/Podfile.lock | 20 +++- example/package.json | 1 + modules/attribution/.gitignore | 78 +++++++++++++ modules/attribution/LICENSE | 41 +++++++ modules/attribution/README.md | 18 +++ modules/attribution/android/build.gradle | 105 ++++++++++++++++++ modules/attribution/android/gradle.properties | 5 + .../android/src/main/AndroidManifest.xml | 3 + .../TealiumReactNativeAttribution.kt | 85 ++++++++++++++ modules/attribution/common.ts | 9 ++ modules/attribution/index.d.ts | 27 +++++ modules/attribution/index.js | 35 ++++++ .../TealiumReactAttribution-Bridging-Header.h | 2 + .../attribution/ios/TealiumReactAttribution.m | 7 ++ .../ios/TealiumReactAttribution.swift | 74 ++++++++++++ modules/attribution/package.json | 49 ++++++++ .../tealium-react-attribution.podspec | 29 +++++ 20 files changed, 605 insertions(+), 8 deletions(-) create mode 100644 modules/attribution/.gitignore create mode 100644 modules/attribution/LICENSE create mode 100644 modules/attribution/README.md create mode 100644 modules/attribution/android/build.gradle create mode 100644 modules/attribution/android/gradle.properties create mode 100644 modules/attribution/android/src/main/AndroidManifest.xml create mode 100644 modules/attribution/android/src/main/java/com/tealium/react/attribution/TealiumReactNativeAttribution.kt create mode 100644 modules/attribution/common.ts create mode 100644 modules/attribution/index.d.ts create mode 100644 modules/attribution/index.js create mode 100644 modules/attribution/ios/TealiumReactAttribution-Bridging-Header.h create mode 100644 modules/attribution/ios/TealiumReactAttribution.m create mode 100644 modules/attribution/ios/TealiumReactAttribution.swift create mode 100644 modules/attribution/package.json create mode 100644 modules/attribution/tealium-react-attribution.podspec diff --git a/example/App.js b/example/App.js index 50b954d2e..721c58c02 100644 --- a/example/App.js +++ b/example/App.js @@ -33,6 +33,8 @@ import AppsFlyerRemoteCommand from 'tealium-react-appsflyer'; import { checkAndRequestPermissions } from "./Utils" // import { AuthState } from 'tealium-react-native-adobe-visitor/common'; import TealiumCrashReporter from 'tealium-react-native-crash-reporter'; +import TealiumAttribution from 'tealium-react-native-attribution'; +import AttributionConfig from 'tealium-react-native-attribution/common' export default class App extends Component<{}> { @@ -53,6 +55,14 @@ export default class App extends Component<{}> { allowSuppressLogLevel: false } + let attributionConfig: AttributionConfig = { + androidInstallReferrerEnabled: true, + androidAdIdentifierEnabled: true, + iosSearchAdsEnabled: true, + iosSkAdAttributionEnabled: true, + iosSkAdConversionKeys: {"event": "conversion_value"} + } + // TealiumAdobeVisitor.configure(adobeVisitorConfig); TealiumLocation.configure(locationConfig); FirebaseRemoteCommand.initialize(); @@ -60,6 +70,8 @@ export default class App extends Component<{}> { AdjustRemoteCommand.initialize(adjustConfig); AppsFlyerRemoteCommand.initialize(); TealiumCrashReporter.initialize(); + TealiumAttribution.configure(attributionConfig); + let config: TealiumConfig = { account: 'tealiummobile', profile: 'demo', @@ -97,7 +109,8 @@ export default class App extends Component<{}> { }, { id: AppsFlyerRemoteCommand.name, path: 'appsflyer.json' - }], + } + ], visitorIdentityKey: DataLayer.UserIdentity }; Tealium.initialize(config, success => { diff --git a/example/android/app/src/debug/AndroidManifest.xml b/example/android/app/src/debug/AndroidManifest.xml index 4b185bc15..5b9b81537 100644 --- a/example/android/app/src/debug/AndroidManifest.xml +++ b/example/android/app/src/debug/AndroidManifest.xml @@ -7,7 +7,9 @@ + tools:ignore="GoogleAppIndexingWarning" + android:allowBackup="false" + tools:replace="android:allowBackup"> diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index ef3c312d1..f96688b12 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -1,5 +1,6 @@ + xmlns:tools="http://schemas.android.com/tools" + package="com.example"> @@ -9,7 +10,8 @@ android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="false" - android:theme="@style/AppTheme"> + android:theme="@style/AppTheme" + tools:replace="android:allowBackup"> 2.4) - tealium-swift/Core (~> 2.12) - TealiumAppsFlyer (~> 3.0) + - tealium-react-attribution (1.0.0): + - React-Core + - tealium-react-native (~> 2.4) + - tealium-react-native-swift (~> 2.4) + - tealium-swift/Attribution (~> 2.12) + - tealium-swift/Core (~> 2.12) - tealium-react-braze (1.1.0): - React - tealium-react-native (~> 2.4) @@ -515,6 +521,8 @@ PODS: - tealium-swift/RemoteCommands (~> 2.12) - tealium-swift/TagManagement (~> 2.12) - tealium-swift/VisitorService (~> 2.12) + - tealium-swift/Attribution (2.12.2): + - tealium-swift/Core - tealium-swift/Collect (2.12.2): - tealium-swift/Core - tealium-swift/Core (2.12.2) @@ -597,6 +605,7 @@ DEPENDENCIES: - tealium-react-adjust (from `../node_modules/tealium-react-adjust`) - tealium-react-adobe-visitor (from `../node_modules/tealium-react-native-adobe-visitor`) - tealium-react-appsflyer (from `../node_modules/tealium-react-appsflyer`) + - tealium-react-attribution (from `../node_modules/tealium-react-native-attribution`) - tealium-react-braze (from `../node_modules/tealium-react-braze`) - tealium-react-firebase (from `../node_modules/tealium-react-firebase`) - tealium-react-native (from `../node_modules/tealium-react-native`) @@ -711,6 +720,8 @@ EXTERNAL SOURCES: :path: "../node_modules/tealium-react-native-adobe-visitor" tealium-react-appsflyer: :path: "../node_modules/tealium-react-appsflyer" + tealium-react-attribution: + :path: "../node_modules/tealium-react-native-attribution" tealium-react-braze: :path: "../node_modules/tealium-react-braze" tealium-react-firebase: @@ -728,7 +739,7 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: Adjust: a830d963025334aee8a62a7bac87825e297a841e - AppsFlyerFramework: 971521cf5b890c2afeab2f2c91734547b8b169ca + AppsFlyerFramework: 0a68f5b72bbbadfa71d4ae3eaf040e82d62e8518 boost: 57d2868c099736d80fcd648bf211b4431e51a558 BrazeKit: ee31d3b5113646cbd6ad44eafc93b14c3c3c504c DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54 @@ -782,6 +793,7 @@ SPEC CHECKSUMS: tealium-react-adjust: f3ef6ba43238d4cbc9483f0aa38738a3eb892fbf tealium-react-adobe-visitor: 140c65d5cd476edd285b4943b75f9aafcd698077 tealium-react-appsflyer: 1be2e9df2dde521ebcd9b4324ddf78ce688ee995 + tealium-react-attribution: 5db8c4ccf60c0fea4790afc5a47537d4a198592c tealium-react-braze: f72256073bf99902dbfbfcd875399cd0fac61796 tealium-react-firebase: 44bc3f5f8294a0f9fc2fba5ebd109bde31a141e5 tealium-react-native: 88d35a0e0e57dcb58d43af0422c15225e60de3b4 diff --git a/example/package.json b/example/package.json index 428f91f7c..d4b689758 100644 --- a/example/package.json +++ b/example/package.json @@ -20,6 +20,7 @@ "tealium-react-native": "../npm-package/", "tealium-react-native-adobe-visitor": "../modules/adobe-visitor/", "tealium-react-native-crash-reporter": "../modules/crash-reporter/", + "tealium-react-native-attribution": "../modules/attribution/", "tealium-react-native-location": "../modules/location/" }, "devDependencies": { diff --git a/modules/attribution/.gitignore b/modules/attribution/.gitignore new file mode 100644 index 000000000..d3b53dfce --- /dev/null +++ b/modules/attribution/.gitignore @@ -0,0 +1,78 @@ +# OSX +# +.DS_Store + +# XDE +.expo/ + +# VSCode +.vscode/ +jsconfig.json + +# Xcode +# +build/ +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata +*.xccheckout +*.moved-aside +DerivedData +*.hmap +*.ipa +*.xcuserstate +project.xcworkspace + +# Android/IJ +# +.classpath +.cxx +.gradle +.idea +.project +.settings +local.properties +android.iml + +# Cocoapods +# +example/ios/Pods + +# Ruby +example/vendor/ + +# node.js +# +node_modules/ +npm-debug.log +yarn-debug.log +yarn-error.log + +# BUCK +buck-out/ +\.buckd/ +android/app/libs +android/keystores/debug.keystore + +# Yarn +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/sdks +!.yarn/versions + +# Expo +.expo/ + +# Turborepo +.turbo/ + +# generated by bob +lib/ diff --git a/modules/attribution/LICENSE b/modules/attribution/LICENSE new file mode 100644 index 000000000..f6f2da35e --- /dev/null +++ b/modules/attribution/LICENSE @@ -0,0 +1,41 @@ +License Agreement + +Thank You for Your interest in our Tealium React Native Library (the "Software"), owned and licensed by Tealium Inc. (“Tealium,” "Our," “We,” or “Us”). Please read this license agreement (the "Agreement") carefully, as it contains the terms and conditions that govern Your use of and access to the Software. + +You may not access the Software if You are Our direct competitor, except with Our prior written consent. In addition, You may not access the Software for purposes of monitoring the availability, performance, or functionality, of any of our products and services or for any other benchmarking or competitive purposes. + +BY DOWNLOADING THE SOFTWARE OR BY EXECUTING A TEALIUM PROVIDED ORDER FORM THAT REFERENCES THIS AGREEMENT, YOU AGREE TO BE BOUND BY AND COMPLY WITH THIS AGREEMENT. IF YOU ARE ENTERING INTO THIS AGREEMENT ON BEHALF OF A COMPANY OR OTHER LEGAL ENTITY, YOU REPRESENT THAT YOU HAVE THE AUTHORITY TO BIND SUCH ENTITY AND ITS AFFILIATES TO THIS AGREEMENT, IN WHICH CASE THE TERMS "YOU" OR "YOUR" WILL REFER TO SUCH ENTITY AND ITS AFFILIATES. IF YOU DO NOT HAVE SUCH AUTHORITY, OR IF YOU DO NOT AGREE WITH THE TERMS OF THIS AGREEMENT, YOU MUST NOT USE THE SOFTWARE. + +The term of Your license to use the Software (the "Term") will begin when You accept this Agreement as set forth above and will continue until terminated pursuant to the provisions of the "Cancellation and Termination" section below. During the Term, We grant You a non-exclusive, non-transferable, royalty-free, limited license (with no right to sublicense) to use the Software to do the following: + +develop software applications and functionality designed to be used in conjunction with Tealium's products and services; +conduct quality assurance testing to ensure compatibility between your software application and Tealium's products and services; and +conduct support testing to troubleshoot compatibility between your software application and Tealium's products and services. + +During the Term, Tealium further grants to You a non-exclusive, non-transferable, royalty-free, limited world-wide license (with no right to sublicense) to market, reproduce, and distribute applications incorporating the integration You develop under this Agreement, either directly or through multiple levels of distributors, Your end users, but only under an end-user license agreement with terms that are as protective of Tealium's rights as this Agreement. + +We do not grant any other rights to the Software. You may only use the Software during the Term, we reserve all rights not expressly granted under this Agreement, and there are no implied rights or other rights We grant hereunder, whether by estoppel or otherwise. You may not: (i) copy or reproduce the Software (except for reasonable archival purposes); (ii) modify or create any derivative works of the Software; (iii) decompile, disassemble, or reverse engineer the Software (except to the extent expressly permitted under applicable law); or (iv) remove or alter any trademark, logo, copyright or other proprietary notices, legends, symbols or labels in the Software. Further, You may not use the Software for any illegal or unauthorized purpose. + +Tealium will retain all title, ownership, and Intellectual Property Rights in the Software and any derivative works thereof. “Intellectual Property Rights” will mean all patent, copyright, trade secret, trademark and other proprietary and intellectual property rights, including moral rights. The Software is protected by copyright and other intellectual property laws and by international treaties. You agree that We will own all suggestions, enhancements requests, feedback, recommendations, or other input provided by You or any other party relating to the Software. Other than the use licenses expressly granted in this Agreement, neither this Agreement nor its performance transfers from Us to You any Tealium intellectual property. + +General Conditions and Restrictions +Your use of the Software is at Your sole risk. +You agree that Tealium is under no obligation to provide You with support for the Software, or to provide You with updates or error corrections ("Updates") to the Software. If Tealium, at its sole discretion, decides to provide You with Updates, Updates will be considered part of Software, and subject to the terms of this Agreement. +You agree not to reproduce, duplicate, copy, sell, resell, or exploit any portion or feature of the Software or access to the Software without express written permission from Tealium. + +No Warranty +THE SOFTWARE IS PROVIDED ON AN “AS IS” AND “AS AVAILABLE” BASIS, AND TEALIUM EXPRESSLY DISCLAIMS ANY WARRANTIES AND CONDITIONS OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, QUIET ENJOYMENT, ACCURACY, OR NON-INFRINGEMENT. WITHOUT LIMITING THE FOREGOING, TEALIUM DOES NOT WARRANT THAT THE SERVICE WILL MEET YOUR SPECIFIC REQUIREMENTS, THAT THE SERVICE WILL BE UNINTERRUPTED, TIMELY, SECURE, OR ERROR-FREE, THAT THE RESULTS THAT MAY BE OBTAINED FROM THE USE OF THE SOFTWARE WILL BE COMPLETE, ACCURATE, OR RELIABLE, THAT THE QUALITY OF ANY PRODUCTS, SERVICES, INFORMATION, OR OTHER MATERIAL PURCHASED OR OBTAINED BY YOU THROUGH THE SOFTWARE WILL MEET YOUR EXPECTATIONS, OR THAT ANY ERRORS IN THE SOFTWARE WILL BE CORRECTED. + +Limitation of Liability +YOU EXPRESSLY UNDERSTAND AND AGREE THAT TEALIUM WILL NOT BE LIABLE FOR ANY INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL OR EXEMPLARY DAMAGES, INCLUDING BUT NOT LIMITED TO DAMAGES FOR LOSS OF PROFITS, GOODWILL, USE, DATA OR OTHER INTANGIBLE LOSSES (EVEN IF TEALIUM HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES), INCLUDING ANY SUCH DAMAGES RESULTING FROM THE USE OR THE INABILITY TO USE THE SOFTWARE; THE COST OF PROCUREMENT OF SUBSTITUTE GOODS AND SERVICES RESULTING FROM ANY GOODS, DATA, INFORMATION OR SERVICES PURCHASED OR OBTAINED OR MESSAGES RECEIVED OR TRANSACTIONS ENTERED INTO THROUGH OR FROM THE SOFTWARE; UNAUTHORIZED ACCESS TO OR ALTERATION OF YOUR TRANSMISSIONS OR DATA; STATEMENTS OR CONDUCT OF ANY THIRD PARTY ON THE SOFTWARE; TERMINATION OF YOUR ACCOUNT; OR ANY OTHER MATTER RELATING TO THE SOFTWARE. + +NOTWITHSTANDING ANYTHING TO THE CONTRARY CONTAINED HEREIN, TEALIUM’S LIABILITY TO YOU FOR ANY DAMAGES ARISING FROM OR RELATING TO THE SOFTWARE (FOR ANY CAUSE WHATSOEVER AND REGARDLESS OF THE FORM OF THE ACTION) WILL AT ALL TIMES BE LIMITED TO THE GREATER OR EITHER (1) THE AMOUNT YOU PAID TO TEALIUM IN THE SIX (6) MONTHS IMMEDIATELY PRECEDING THE INCIDENT GIVING RISE TO THE CLAIM OR (2) ONE HUNDRED FIFTY DOLLARS (USD 150.00). + +Cancellation and Termination +Tealium, in its sole discretion, may terminate your license, for any reason at any time. +You, in your sole discretion, may terminate this Agreement immediately upon written notice to Tealium. +Upon termination or expiration of this Agreement, You will immediately cease use of and destroy the original and all copies of the Software in Your possession or control. Upon Tealium's written request, You will confirm to Tealium in writing that You have complied with all provisions of this Agreement. +Either party may terminate this Agreement upon written notice to the other party, for any material breach by the other party, if such breach is not cured within thirty (30) days after the non-breaching party provides the allegedly breaching party with written notice of such breach. + +Miscellaneous +This Agreement will be governed by the laws of the State of California without giving effect to any conflicts of laws principles that may require the application of the law of a different jurisdiction. For any dispute or proceeding arising from or relating to this Agreement, You agree to submit to the jurisdiction of, and agree that venue is proper in, the state courts located in San Diego County, California, and in the federal courts located in the Southern District of California. The failure of Tealium to exercise or enforce any right or provision of this Agreement will not constitute a waiver of such right or provision. This Agreement constitutes the entire agreement between You and Tealium and governs Your use of the Service, superseding any prior agreements between You and Tealium (including, but not limited to, any prior versions of the Agreement). \ No newline at end of file diff --git a/modules/attribution/README.md b/modules/attribution/README.md new file mode 100644 index 000000000..045aa05dc --- /dev/null +++ b/modules/attribution/README.md @@ -0,0 +1,18 @@ +## Tealium React Native + +This repository contains the necessary assets for exposing Tealium's native [Android](https://docs.tealium.com/platforms/android-kotlin/) and [iOS](https://docs.tealium.com/platforms/ios-swift/) mobile libraries to the JavaScript code in your React Native project. This includes code for exposing the native APIs for both platforms through React Native's bridging system, and a basic helper class in JavaScript to create a single cross platform API. + +You can also find a example application demonstrating how everything is put together and how the API gets called in JavaScript. + +## Documentation +For full documentation, please see the Tealium Developer Docs website: + +[Tealium React Native Documentation](https://docs.tealium.com/platforms/react-native/install/) + +## License + +Use of this software is subject to the terms and conditions of the license agreement contained in the file titled "LICENSE.txt". Please read the license before downloading or using any of the files contained in this repository. By downloading or using any of these files, you are agreeing to be bound by and comply with the license agreement. + + +--- +Copyright (C) 2012-2024, Tealium Inc. \ No newline at end of file diff --git a/modules/attribution/android/build.gradle b/modules/attribution/android/build.gradle new file mode 100644 index 000000000..a22b388d6 --- /dev/null +++ b/modules/attribution/android/build.gradle @@ -0,0 +1,105 @@ +def DEFAULT_COMPILE_SDK_VERSION = 31 +def DEFAULT_BUILD_TOOLS_VERSION = '30.0.2' +def DEFAULT_MIN_SDK_VERSION = 21 +def DEFAULT_TARGET_SDK_VERSION = 31 + +def safeExtGet(prop, fallback) { + rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback +} + +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' + +buildscript { + ext { + kotlinVersion = rootProject.ext.has('kotlinVersion') ? rootProject.ext.get('kotlinVersion') : '1.6.0' + } + + if (project == rootProject) { + repositories { + google() + mavenCentral() + maven { + url "https://maven.tealiumiq.com/android/releases/" + } + } + dependencies { + classpath 'com.android.tools.build:gradle:4.2.2' + } + } + + repositories { + mavenCentral() + } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${project.ext.kotlinVersion}" + } +} + +version = "1.0.0" + +android { + compileSdkVersion safeExtGet('compileSdkVersion', DEFAULT_COMPILE_SDK_VERSION) + buildToolsVersion safeExtGet('buildToolsVersion', DEFAULT_BUILD_TOOLS_VERSION) + + defaultConfig { + minSdkVersion safeExtGet('minSdkVersion', DEFAULT_MIN_SDK_VERSION) + targetSdkVersion safeExtGet('targetSdkVersion', DEFAULT_TARGET_SDK_VERSION) + versionCode 1 + versionName "1.0" + + buildConfigField "String", "TAG", "\"Tealium-React-Attribution-$version\"" + } + + lintOptions { + disable 'GradleCompatible' + } + + def agpVersion = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.')[0].toInteger() + if(agpVersion < 8) { + compileOptions { + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_11 + } + } +} + +repositories { + // ref: https://www.baeldung.com/maven-local-repository + mavenLocal() + maven { + // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm + url "$rootDir/../node_modules/react-native/android" + } + + maven { + // Android JSC is installed from npm + url "$rootDir/../node_modules/jsc-android/dist" + } + + maven { + url "https://maven.tealiumiq.com/android/releases/" + } + + google() + mavenCentral() +} + + +dependencies { + // noinspection GradleDynamicVersion + implementation 'com.facebook.react:react-native:+' + + // Tealium React Native + implementation project(":tealium-react-native") + + // Tealium Install Referrer + implementation 'com.tealium:kotlin-install-referrer:1.1.1' + implementation 'com.tealium:kotlin-ad-identifier:1.1.2' + + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${project.ext.kotlinVersion}" +} diff --git a/modules/attribution/android/gradle.properties b/modules/attribution/android/gradle.properties new file mode 100644 index 000000000..208ef3c76 --- /dev/null +++ b/modules/attribution/android/gradle.properties @@ -0,0 +1,5 @@ +TealiumReactNativeAttribution_kotlinVersion=1.7.0 +TealiumReactNativeAttribution_minSdkVersion=21 +TealiumReactNativeAttribution_targetSdkVersion=31 +TealiumReactNativeAttribution_compileSdkVersion=31 +TealiumReactNativeAttribution_ndkversion=21.4.7075529 diff --git a/modules/attribution/android/src/main/AndroidManifest.xml b/modules/attribution/android/src/main/AndroidManifest.xml new file mode 100644 index 000000000..d90e8853c --- /dev/null +++ b/modules/attribution/android/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ + + diff --git a/modules/attribution/android/src/main/java/com/tealium/react/attribution/TealiumReactNativeAttribution.kt b/modules/attribution/android/src/main/java/com/tealium/react/attribution/TealiumReactNativeAttribution.kt new file mode 100644 index 000000000..d9aec06f7 --- /dev/null +++ b/modules/attribution/android/src/main/java/com/tealium/react/attribution/TealiumReactNativeAttribution.kt @@ -0,0 +1,85 @@ +package com.tealium.react.attribution + +import com.facebook.react.ReactPackage +import com.facebook.react.bridge.NativeModule +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.bridge.ReactContextBaseJavaModule +import com.facebook.react.bridge.ReactMethod +import com.facebook.react.bridge.ReadableMap +import com.facebook.react.uimanager.ViewManager +import com.tealium.adidentifier.AdIdentifier +import com.tealium.adidentifier.adIdentifier +import com.tealium.core.Modules +import com.tealium.core.Tealium +import com.tealium.core.TealiumConfig +import com.tealium.installreferrer.InstallReferrer +import com.tealium.react.INSTANCE_NAME +import com.tealium.react.OptionalModule +import com.tealium.react.TealiumReact +import com.tealium.react.safeGetBoolean + +class TealiumReactNativeAttributionPackage : ReactPackage { + override fun createNativeModules(reactContext: ReactApplicationContext): List { + return listOf(TealiumReactAttribution(reactContext)) + } + + override fun createViewManagers(reactContext: ReactApplicationContext): List> { + return emptyList() + } +} + +class TealiumReactAttribution(private val reactContext: ReactApplicationContext) : + ReactContextBaseJavaModule(reactContext), OptionalModule { + + private var _installReferrerEnabled: Boolean? = null + private var _adIdentifierEnabled: Boolean? = null + + @ReactMethod + override fun initialize() { + super.initialize() + reactContext.getNativeModule(TealiumReact::class.java)?.registerOptionalModule(this) + } + + override fun configure(config: TealiumConfig) { + if (_installReferrerEnabled == true) { + config.modules.add(Modules.InstallReferrer) + } + if (_adIdentifierEnabled == true) { + config.modules.add(Modules.AdIdentifier) + } + } + + @ReactMethod + fun configure(config: ReadableMap?) { + config?.let { + it.safeGetBoolean(KEY_INSTALL_REFERRER_ENABLED)?.let { installReferrerEnabled -> + _installReferrerEnabled = installReferrerEnabled + } + + it.safeGetBoolean(KEY_AD_IDENTIFIER_ENABLED)?.let { adIdEnabled -> + _adIdentifierEnabled = adIdEnabled + } + } + } + + @ReactMethod + fun removeAdInfo() { + Tealium[INSTANCE_NAME]?.adIdentifier?.removeAdInfo() + } + + @ReactMethod + fun removeAppSetIdInfo() { + Tealium[INSTANCE_NAME]?.adIdentifier?.removeAppSetIdInfo() + } + + override fun getName(): String { + return NAME + } + + companion object { + const val NAME = "TealiumReactAttribution" + + private const val KEY_INSTALL_REFERRER_ENABLED = "androidInstallReferrerEnabled" + private const val KEY_AD_IDENTIFIER_ENABLED = "androidAdIdentifierEnabled" + } +} diff --git a/modules/attribution/common.ts b/modules/attribution/common.ts new file mode 100644 index 000000000..2bf465d3c --- /dev/null +++ b/modules/attribution/common.ts @@ -0,0 +1,9 @@ +export interface AttributionConfig { + androidInstallReferrerEnabled?: boolean; + androidAdIdentifierEnabled?: boolean; + iosSearchAdsEnabled?: boolean; + iosSkAdAttributionEnabled?: boolean; + iosSkAdConversionKeys?: { [key: string]: string }; +} + +export class TealiumAttributionCommon{} \ No newline at end of file diff --git a/modules/attribution/index.d.ts b/modules/attribution/index.d.ts new file mode 100644 index 000000000..c840cb2da --- /dev/null +++ b/modules/attribution/index.d.ts @@ -0,0 +1,27 @@ +import { AttributionConfig, TealiumAttributionCommon } from "./common"; + +declare module 'tealium-react-native-attribution'{ + export default TealiumAttribution; + class TealiumAttribution extends TealiumAttributionCommon { + + /** + * Configures Tealium Attrubtion module. + * @param config Configuration properties for Attribution modile + */ + public static configure(config?: AttributionConfig): void; + + /** + * Android only. Clears values and removes ad information from + * the data layer related to Ad Identifier module in Tealium + * Android library. + */ + public static removeAdInfo(): void; + + /** + * Android only. Clears values and removes app set ID from + * the data layer related to Ad Identifier modules in Tealium + * Android library. + */ + public static removeAppSetIdInfo(): void; + } +} \ No newline at end of file diff --git a/modules/attribution/index.js b/modules/attribution/index.js new file mode 100644 index 000000000..6154b6109 --- /dev/null +++ b/modules/attribution/index.js @@ -0,0 +1,35 @@ +import { NativeModules } from 'react-native'; +const { TealiumReactAttribution } = NativeModules; + +export default class TealiumAttribution { + + /** + * Configures the Tealium Attrubtion module. + * @param config configuration properties for Attribution modile + */ + static configure(config) { + TealiumReactAttribution.configure(config || {}) + } + + /** + * Android only. Clears values and removes ad information from + * the data layer related to Ad Identifier module in Tealium + * Android library. + */ + static removeAdInfo() { + if (Platform.OS === 'android') { + TealiumReactAttribution.removeAdInfo() + } + } + + /** + * Android only. Clears values and removes app set ID from + * the data layer related to Ad Identifier modules in Tealium + * Android library. + */ + static removeAppSetIdInfo() { + if (Platform.OS === 'android') { + TealiumReactAttribution.removeAppSetIdInfo() + } + } +} \ No newline at end of file diff --git a/modules/attribution/ios/TealiumReactAttribution-Bridging-Header.h b/modules/attribution/ios/TealiumReactAttribution-Bridging-Header.h new file mode 100644 index 000000000..dea7ff6bf --- /dev/null +++ b/modules/attribution/ios/TealiumReactAttribution-Bridging-Header.h @@ -0,0 +1,2 @@ +#import +#import diff --git a/modules/attribution/ios/TealiumReactAttribution.m b/modules/attribution/ios/TealiumReactAttribution.m new file mode 100644 index 000000000..73e2beee7 --- /dev/null +++ b/modules/attribution/ios/TealiumReactAttribution.m @@ -0,0 +1,7 @@ +#import + +@interface RCT_EXTERN_MODULE(TealiumReactAttribution, NSObject) + +RCT_EXTERN_METHOD(configure:(NSDictionary *)config) + +@end diff --git a/modules/attribution/ios/TealiumReactAttribution.swift b/modules/attribution/ios/TealiumReactAttribution.swift new file mode 100644 index 000000000..bd19c6723 --- /dev/null +++ b/modules/attribution/ios/TealiumReactAttribution.swift @@ -0,0 +1,74 @@ +import Foundation +import tealium_react_native_swift +import TealiumSwift + +@objc(TealiumReactAttribution) +class TealiumReactAttribution: NSObject, RCTBridgeModule { + static func moduleName() -> String! { + return "TealiumReactAttribution" + } + + private let KEY_ATTRIBUTION_SEARCH_ADS_ENABLED = "iosSearchAdsEnabled" + private let KEY_ATTRIBUTION_SKAD_ATTRIBUTION_ENABLED = "iosSkAdAttributionEnabled" + private let KEY_ATTRIBUTION_SKAD_CONVERSION_KEYS = "iosSkAdConversionKeys" + let module = TealiumReactAttributionModule() + + @objc + static func requiresMainQueueSetup() -> Bool { + return false + } + + override init() { + super.init() + TealiumReactNative.registerOptionalModule(module) + } + + @objc(configure:) + public func configure(_ config: [String: Any]) { + if let searchAds = config[KEY_ATTRIBUTION_SEARCH_ADS_ENABLED] as? Bool { + module.setSearchAdsEnabled(enabled: searchAds) + } + + if let skAdAttribution = config[KEY_ATTRIBUTION_SKAD_ATTRIBUTION_ENABLED] as? Bool { + module.setSkAdAttributionEnabled(enabled: skAdAttribution) + } + + if let skAdKeys = config[KEY_ATTRIBUTION_SKAD_CONVERSION_KEYS] as? [String: String] { + module.setSkAdConversionKeys(keys: skAdKeys) + } + } +} + +@objc class TealiumReactAttributionModule: NSObject, OptionalModule { + private var searchAdsEnabled: Bool? = nil + private var skAdAttributionEnabled: Bool? = nil + private var skAdConversionKeys: [String: String]? = nil + + func configure(config: TealiumConfig) { + config.collectors?.append(Collectors.Attribution) + + if let searchAds = searchAdsEnabled { + config.searchAdsEnabled = searchAds + } + + if let skAdAttrubution = skAdAttributionEnabled { + config.skAdAttributionEnabled = skAdAttrubution + } + + if let conversionKeys = skAdConversionKeys { + config.skAdConversionKeys = conversionKeys + } + } + + func setSearchAdsEnabled(enabled: Bool) { + searchAdsEnabled = enabled + } + + func setSkAdAttributionEnabled(enabled: Bool) { + skAdAttributionEnabled = enabled + } + + func setSkAdConversionKeys(keys: [String: String]) { + skAdConversionKeys = keys + } +} diff --git a/modules/attribution/package.json b/modules/attribution/package.json new file mode 100644 index 000000000..6a9dc2dd6 --- /dev/null +++ b/modules/attribution/package.json @@ -0,0 +1,49 @@ +{ + "name": "tealium-react-native-attribution", + "title": "Tealium React Native Attribution Module", + "version": "1.0.0", + "description": "A native module for using Tealium's Install Referrer and Ad Identifier for Kotlin library, as well as Attribution for Swift library.", + "main": "index.js", + "types": "*.ts", + "homepage": "https://github.com/Tealium/tealium-react-native", + "bugs": "https://github.com/Tealium/tealium-react-native/issues", + "files": [ + "README.md", + "LICENSE", + "android", + "common.ts", + "index.js", + "index.d.ts", + "ios", + "tealium-react-attribution.podspec" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/Tealium/tealium-react-native.git", + "baseUrl": "https://github.com/Tealium/tealium-react-native" + }, + "keywords": [ + "react-native", + "tealium" + ], + "author": { + "name": "Tealium" + }, + "contributors": [ + "Karen Tamayo" + ], + "license": "Commercial", + "licenseFilename": "LICENSE", + "readmeFilename": "README.md", + "peerDependencies": { + "react": ">=16.8.1 || < 19.0.0", + "react-native": ">=0.60.0-rc.0 <1.0.x" + }, + "devDependencies": { + "react": "^17.0.2", + "react-native": "^0.67.1" + }, + "dependencies": { + "tealium-react-native": "^2.2.0" + } +} diff --git a/modules/attribution/tealium-react-attribution.podspec b/modules/attribution/tealium-react-attribution.podspec new file mode 100644 index 000000000..f1d19e31b --- /dev/null +++ b/modules/attribution/tealium-react-attribution.podspec @@ -0,0 +1,29 @@ +require "json" + +package = JSON.parse(File.read(File.join(__dir__, "package.json"))) + +Pod::Spec.new do |s| + s.name = "tealium-react-attribution" + s.version = package["version"] + s.summary = package["description"] + s.description = <<-DESC + Tealium React Native Attribution Plugin + DESC + s.homepage = "https://github.com/Tealium/tealium-react-native/modules" + s.license = { :type => "Commercial", :file => "LICENSE" } + s.authors = { "Tealium" => "mobile-dev@tealium.com" } + s.platforms = { :ios => "12.0" } + s.source = { :git => "https://github.com/Tealium/tealium-react-native.git", :tag => "#{s.version}" } + s.source_files = "ios/**/*.{h,c,m,swift}" + s.requires_arc = true + s.swift_version = "5.0" + s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' } + + s.dependency "React-Core" + s.dependency "tealium-react-native", "~> 2.4" + s.dependency "tealium-react-native-swift", "~> 2.4" + s.dependency "tealium-swift/Core", "~> 2.12" + s.dependency "tealium-swift/Attribution", "~> 2.12" + +end +