@amplitude/analytics-react-native 0.0.1-dev.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -0
- package/amplitude-react-native.podspec +21 -0
- package/android/build.gradle +61 -0
- package/android/gradle.properties +3 -0
- package/android/src/main/AndroidManifest.xml +4 -0
- package/android/src/main/java/com/amplitude/reactnative/AmplitudeReactNativeModule.kt +36 -0
- package/android/src/main/java/com/amplitude/reactnative/AmplitudeReactNativePackage.java +28 -0
- package/android/src/main/java/com/amplitude/reactnative/AndroidContextProvider.kt +415 -0
- package/android/src/main/java/com/amplitude/reactnative/AndroidLogger.kt +56 -0
- package/android/src/main/java/com/amplitude/reactnative/Utils.kt +34 -0
- package/ios/AmplitudeReactNative-Bridging-Header.h +5 -0
- package/ios/AmplitudeReactNative.m +7 -0
- package/ios/AmplitudeReactNative.swift +29 -0
- package/ios/AmplitudeReactNative.xcodeproj/project.pbxproj +293 -0
- package/ios/AppleContextProvider.swift +219 -0
- package/lib/commonjs/attribution/campaign-parser.js +74 -0
- package/lib/commonjs/attribution/campaign-parser.js.map +1 -0
- package/lib/commonjs/attribution/campaign-tracker.js +133 -0
- package/lib/commonjs/attribution/campaign-tracker.js.map +1 -0
- package/lib/commonjs/attribution/constants.js +47 -0
- package/lib/commonjs/attribution/constants.js.map +1 -0
- package/lib/commonjs/config.js +257 -0
- package/lib/commonjs/config.js.map +1 -0
- package/lib/commonjs/constants.js +31 -0
- package/lib/commonjs/constants.js.map +1 -0
- package/lib/commonjs/cookie-migration/index.js +74 -0
- package/lib/commonjs/cookie-migration/index.js.map +1 -0
- package/lib/commonjs/index.js +141 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/plugins/context.js +136 -0
- package/lib/commonjs/plugins/context.js.map +1 -0
- package/lib/commonjs/react-native-client.js +362 -0
- package/lib/commonjs/react-native-client.js.map +1 -0
- package/lib/commonjs/session-manager.js +114 -0
- package/lib/commonjs/session-manager.js.map +1 -0
- package/lib/commonjs/storage/cookie.js +124 -0
- package/lib/commonjs/storage/cookie.js.map +1 -0
- package/lib/commonjs/storage/local-storage.js +79 -0
- package/lib/commonjs/storage/local-storage.js.map +1 -0
- package/lib/commonjs/storage/utm-cookie.js +42 -0
- package/lib/commonjs/storage/utm-cookie.js.map +1 -0
- package/lib/commonjs/transports/fetch.js +34 -0
- package/lib/commonjs/transports/fetch.js.map +1 -0
- package/lib/commonjs/transports/send-beacon.js +43 -0
- package/lib/commonjs/transports/send-beacon.js.map +1 -0
- package/lib/commonjs/transports/xhr.js +54 -0
- package/lib/commonjs/transports/xhr.js.map +1 -0
- package/lib/commonjs/typings/browser-snippet.d.js +6 -0
- package/lib/commonjs/typings/browser-snippet.d.js.map +1 -0
- package/lib/commonjs/typings/ua-parser.d.js +2 -0
- package/lib/commonjs/typings/ua-parser.d.js.map +1 -0
- package/lib/commonjs/utils/cookie-name.js +23 -0
- package/lib/commonjs/utils/cookie-name.js.map +1 -0
- package/lib/commonjs/utils/language.js +18 -0
- package/lib/commonjs/utils/language.js.map +1 -0
- package/lib/commonjs/utils/platform.js +21 -0
- package/lib/commonjs/utils/platform.js.map +1 -0
- package/lib/commonjs/utils/query-params.js +36 -0
- package/lib/commonjs/utils/query-params.js.map +1 -0
- package/lib/commonjs/utils/snippet-helper.js +56 -0
- package/lib/commonjs/utils/snippet-helper.js.map +1 -0
- package/lib/commonjs/version.js +9 -0
- package/lib/commonjs/version.js.map +1 -0
- package/lib/module/attribution/campaign-parser.js +62 -0
- package/lib/module/attribution/campaign-parser.js.map +1 -0
- package/lib/module/attribution/campaign-tracker.js +120 -0
- package/lib/module/attribution/campaign-tracker.js.map +1 -0
- package/lib/module/attribution/constants.js +26 -0
- package/lib/module/attribution/constants.js.map +1 -0
- package/lib/module/config.js +217 -0
- package/lib/module/config.js.map +1 -0
- package/lib/module/constants.js +13 -0
- package/lib/module/constants.js.map +1 -0
- package/lib/module/cookie-migration/index.js +56 -0
- package/lib/module/cookie-migration/index.js.map +1 -0
- package/lib/module/index.js +6 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/plugins/context.js +118 -0
- package/lib/module/plugins/context.js.map +1 -0
- package/lib/module/react-native-client.js +329 -0
- package/lib/module/react-native-client.js.map +1 -0
- package/lib/module/session-manager.js +104 -0
- package/lib/module/session-manager.js.map +1 -0
- package/lib/module/storage/cookie.js +114 -0
- package/lib/module/storage/cookie.js.map +1 -0
- package/lib/module/storage/local-storage.js +67 -0
- package/lib/module/storage/local-storage.js.map +1 -0
- package/lib/module/storage/utm-cookie.js +32 -0
- package/lib/module/storage/utm-cookie.js.map +1 -0
- package/lib/module/transports/fetch.js +24 -0
- package/lib/module/transports/fetch.js.map +1 -0
- package/lib/module/transports/send-beacon.js +33 -0
- package/lib/module/transports/send-beacon.js.map +1 -0
- package/lib/module/transports/xhr.js +44 -0
- package/lib/module/transports/xhr.js.map +1 -0
- package/lib/module/typings/browser-snippet.d.js +2 -0
- package/lib/module/typings/browser-snippet.d.js.map +1 -0
- package/lib/module/typings/ua-parser.d.js +2 -0
- package/lib/module/typings/ua-parser.d.js.map +1 -0
- package/lib/module/utils/cookie-name.js +10 -0
- package/lib/module/utils/cookie-name.js.map +1 -0
- package/lib/module/utils/language.js +9 -0
- package/lib/module/utils/language.js.map +1 -0
- package/lib/module/utils/platform.js +8 -0
- package/lib/module/utils/platform.js.map +1 -0
- package/lib/module/utils/query-params.js +26 -0
- package/lib/module/utils/query-params.js.map +1 -0
- package/lib/module/utils/snippet-helper.js +41 -0
- package/lib/module/utils/snippet-helper.js.map +1 -0
- package/lib/module/version.js +2 -0
- package/lib/module/version.js.map +1 -0
- package/lib/typescript/attribution/campaign-parser.d.ts +10 -0
- package/lib/typescript/attribution/campaign-parser.d.ts.map +1 -0
- package/lib/typescript/attribution/campaign-tracker.d.ts +72 -0
- package/lib/typescript/attribution/campaign-tracker.d.ts.map +1 -0
- package/lib/typescript/attribution/constants.d.ts +17 -0
- package/lib/typescript/attribution/constants.d.ts.map +1 -0
- package/lib/typescript/config.d.ts +90 -0
- package/lib/typescript/config.d.ts.map +1 -0
- package/lib/typescript/constants.d.ts +13 -0
- package/lib/typescript/constants.d.ts.map +1 -0
- package/lib/typescript/cookie-migration/index.d.ts +5 -0
- package/lib/typescript/cookie-migration/index.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +6 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/plugins/context.d.ts +31 -0
- package/lib/typescript/plugins/context.d.ts.map +1 -0
- package/lib/typescript/react-native-client.d.ts +209 -0
- package/lib/typescript/react-native-client.d.ts.map +1 -0
- package/lib/typescript/session-manager.d.ts +28 -0
- package/lib/typescript/session-manager.d.ts.map +1 -0
- package/lib/typescript/storage/cookie.d.ts +12 -0
- package/lib/typescript/storage/cookie.d.ts.map +1 -0
- package/lib/typescript/storage/local-storage.d.ts +10 -0
- package/lib/typescript/storage/local-storage.d.ts.map +1 -0
- package/lib/typescript/storage/utm-cookie.d.ts +6 -0
- package/lib/typescript/storage/utm-cookie.d.ts.map +1 -0
- package/lib/typescript/transports/fetch.d.ts +6 -0
- package/lib/typescript/transports/fetch.d.ts.map +1 -0
- package/lib/typescript/transports/send-beacon.d.ts +6 -0
- package/lib/typescript/transports/send-beacon.d.ts.map +1 -0
- package/lib/typescript/transports/xhr.d.ts +7 -0
- package/lib/typescript/transports/xhr.d.ts.map +1 -0
- package/lib/typescript/utils/cookie-name.d.ts +3 -0
- package/lib/typescript/utils/cookie-name.d.ts.map +1 -0
- package/lib/typescript/utils/language.d.ts +2 -0
- package/lib/typescript/utils/language.d.ts.map +1 -0
- package/lib/typescript/utils/platform.d.ts +3 -0
- package/lib/typescript/utils/platform.d.ts.map +1 -0
- package/lib/typescript/utils/query-params.d.ts +2 -0
- package/lib/typescript/utils/query-params.d.ts.map +1 -0
- package/lib/typescript/utils/snippet-helper.d.ts +16 -0
- package/lib/typescript/utils/snippet-helper.d.ts.map +1 -0
- package/lib/typescript/version.d.ts +2 -0
- package/lib/typescript/version.d.ts.map +1 -0
- package/package.json +93 -0
- package/src/attribution/campaign-parser.ts +78 -0
- package/src/attribution/campaign-tracker.ts +112 -0
- package/src/attribution/constants.ts +32 -0
- package/src/config.ts +210 -0
- package/src/constants.ts +14 -0
- package/src/cookie-migration/index.ts +54 -0
- package/src/index.ts +23 -0
- package/src/plugins/context.ts +106 -0
- package/src/react-native-client.ts +349 -0
- package/src/session-manager.ts +81 -0
- package/src/storage/cookie.ts +95 -0
- package/src/storage/local-storage.ts +67 -0
- package/src/storage/utm-cookie.ts +27 -0
- package/src/transports/fetch.ts +23 -0
- package/src/transports/send-beacon.ts +34 -0
- package/src/transports/xhr.ts +36 -0
- package/src/typings/browser-snippet.d.ts +7 -0
- package/src/typings/ua-parser.d.ts +4 -0
- package/src/utils/cookie-name.ts +9 -0
- package/src/utils/language.ts +7 -0
- package/src/utils/platform.ts +9 -0
- package/src/utils/query-params.ts +21 -0
- package/src/utils/snippet-helper.ts +35 -0
- package/src/version.ts +1 -0
package/README.md
ADDED
|
File without changes
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
|
|
4
|
+
|
|
5
|
+
Pod::Spec.new do |s|
|
|
6
|
+
s.name = "amplitude-react-native"
|
|
7
|
+
s.version = package["version"]
|
|
8
|
+
s.summary = package["description"]
|
|
9
|
+
s.homepage = package["homepage"]
|
|
10
|
+
s.license = package["license"]
|
|
11
|
+
s.authors = package["author"]
|
|
12
|
+
|
|
13
|
+
s.swift_version = "5.0"
|
|
14
|
+
|
|
15
|
+
s.platforms = { :ios => "10.0", :tvos => "10.0" }
|
|
16
|
+
s.source = { :git => "https://github.com/amplitude/Amplitude-TypeScript.git", :tag => "#{s.version}" }
|
|
17
|
+
|
|
18
|
+
s.source_files = "ios/**/*.{h,m,mm,swift}"
|
|
19
|
+
|
|
20
|
+
s.dependency "React-Core"
|
|
21
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
buildscript {
|
|
2
|
+
ext.kotlinVersion = "1.5.30"
|
|
3
|
+
if (project == rootProject) {
|
|
4
|
+
repositories {
|
|
5
|
+
google()
|
|
6
|
+
jcenter()
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
dependencies {
|
|
10
|
+
classpath 'com.android.tools.build:gradle:3.5.3'
|
|
11
|
+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
apply plugin: 'com.android.library'
|
|
17
|
+
apply plugin: 'kotlin-android'
|
|
18
|
+
|
|
19
|
+
def safeExtGet(prop, fallback) {
|
|
20
|
+
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
android {
|
|
24
|
+
compileSdkVersion safeExtGet('compileSdkVersion', 29)
|
|
25
|
+
buildToolsVersion safeExtGet('buildToolsVersion', '29.0.2')
|
|
26
|
+
defaultConfig {
|
|
27
|
+
minSdkVersion safeExtGet('minSdkVersion', 16)
|
|
28
|
+
targetSdkVersion safeExtGet('targetSdkVersion', 29)
|
|
29
|
+
versionCode 1
|
|
30
|
+
versionName "1.0"
|
|
31
|
+
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
buildTypes {
|
|
35
|
+
release {
|
|
36
|
+
minifyEnabled false
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
lintOptions {
|
|
40
|
+
disable 'GradleCompatible'
|
|
41
|
+
}
|
|
42
|
+
compileOptions {
|
|
43
|
+
sourceCompatibility JavaVersion.VERSION_1_8
|
|
44
|
+
targetCompatibility JavaVersion.VERSION_1_8
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
repositories {
|
|
49
|
+
mavenLocal()
|
|
50
|
+
maven {
|
|
51
|
+
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
|
|
52
|
+
url("$rootDir/../node_modules/react-native/android")
|
|
53
|
+
}
|
|
54
|
+
google()
|
|
55
|
+
jcenter()
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
dependencies {
|
|
59
|
+
//noinspection GradleDynamicVersion
|
|
60
|
+
implementation "com.facebook.react:react-native:+" // From node_modules
|
|
61
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
package com.amplitude.reactnative
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.Promise
|
|
4
|
+
import com.facebook.react.module.annotations.ReactModule
|
|
5
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
|
+
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
7
|
+
import com.facebook.react.bridge.ReactMethod
|
|
8
|
+
import com.facebook.react.bridge.ReadableMap
|
|
9
|
+
import com.facebook.react.bridge.WritableNativeMap
|
|
10
|
+
|
|
11
|
+
const val MODULE_NAME = "AmplitudeReactNative"
|
|
12
|
+
|
|
13
|
+
@ReactModule(name = MODULE_NAME)
|
|
14
|
+
class AmplitudeReactNativeModule(private val reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
|
|
15
|
+
|
|
16
|
+
private val androidContextProvider = AndroidContextProvider(reactContext.applicationContext, false)
|
|
17
|
+
|
|
18
|
+
override fun getName(): String {
|
|
19
|
+
return MODULE_NAME
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@ReactMethod
|
|
23
|
+
private fun getApplicationContext(promise: Promise) {
|
|
24
|
+
promise.resolve(WritableNativeMap().apply {
|
|
25
|
+
putString("version", androidContextProvider.versionName)
|
|
26
|
+
putString("platform", androidContextProvider.osName)
|
|
27
|
+
putString("language", androidContextProvider.language)
|
|
28
|
+
putString("os_name", androidContextProvider.osName)
|
|
29
|
+
putString("os_version", androidContextProvider.osVersion)
|
|
30
|
+
putString("device_brand", androidContextProvider.brand)
|
|
31
|
+
putString("device_manufacturer", androidContextProvider.manufacturer)
|
|
32
|
+
putString("device_model", androidContextProvider.model)
|
|
33
|
+
putString("carrier", androidContextProvider.carrier)
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
package com.amplitude.reactnative;
|
|
2
|
+
|
|
3
|
+
import androidx.annotation.NonNull;
|
|
4
|
+
|
|
5
|
+
import com.facebook.react.ReactPackage;
|
|
6
|
+
import com.facebook.react.bridge.NativeModule;
|
|
7
|
+
import com.facebook.react.bridge.ReactApplicationContext;
|
|
8
|
+
import com.facebook.react.uimanager.ViewManager;
|
|
9
|
+
|
|
10
|
+
import java.util.ArrayList;
|
|
11
|
+
import java.util.Collections;
|
|
12
|
+
import java.util.List;
|
|
13
|
+
|
|
14
|
+
public class AmplitudeReactNativePackage implements ReactPackage {
|
|
15
|
+
@NonNull
|
|
16
|
+
@Override
|
|
17
|
+
public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
|
|
18
|
+
List<NativeModule> modules = new ArrayList<>();
|
|
19
|
+
modules.add(new AmplitudeReactNativeModule(reactContext));
|
|
20
|
+
return modules;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@NonNull
|
|
24
|
+
@Override
|
|
25
|
+
public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
|
|
26
|
+
return Collections.emptyList();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
package com.amplitude.reactnative
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.content.pm.PackageInfo
|
|
5
|
+
import android.content.pm.PackageManager
|
|
6
|
+
import android.content.res.Resources
|
|
7
|
+
import android.location.Geocoder
|
|
8
|
+
import android.location.Location
|
|
9
|
+
import android.location.LocationManager
|
|
10
|
+
import android.os.Build
|
|
11
|
+
import android.provider.Settings.Secure
|
|
12
|
+
import android.telephony.TelephonyManager
|
|
13
|
+
import java.io.IOException
|
|
14
|
+
import java.lang.Exception
|
|
15
|
+
import java.lang.IllegalArgumentException
|
|
16
|
+
import java.lang.IllegalStateException
|
|
17
|
+
import java.lang.NullPointerException
|
|
18
|
+
import java.lang.reflect.InvocationTargetException
|
|
19
|
+
import java.util.Locale
|
|
20
|
+
import java.util.UUID
|
|
21
|
+
import kotlin.collections.ArrayList
|
|
22
|
+
|
|
23
|
+
class AndroidContextProvider(private val context: Context, locationListening: Boolean) {
|
|
24
|
+
var isLocationListening = true
|
|
25
|
+
private var cachedInfo: CachedInfo? = null
|
|
26
|
+
private get() {
|
|
27
|
+
if (field == null) {
|
|
28
|
+
field = CachedInfo()
|
|
29
|
+
}
|
|
30
|
+
return field
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Internal class serves as a cache
|
|
35
|
+
*/
|
|
36
|
+
inner class CachedInfo {
|
|
37
|
+
var advertisingId: String
|
|
38
|
+
val country: String?
|
|
39
|
+
val versionName: String?
|
|
40
|
+
val osName: String
|
|
41
|
+
val osVersion: String
|
|
42
|
+
val brand: String
|
|
43
|
+
val manufacturer: String
|
|
44
|
+
val model: String
|
|
45
|
+
val carrier: String?
|
|
46
|
+
val language: String
|
|
47
|
+
var limitAdTrackingEnabled: Boolean = true
|
|
48
|
+
val gpsEnabled: Boolean
|
|
49
|
+
var appSetId: String
|
|
50
|
+
|
|
51
|
+
init {
|
|
52
|
+
advertisingId = fetchAdvertisingId()
|
|
53
|
+
versionName = fetchVersionName()
|
|
54
|
+
osName = OS_NAME
|
|
55
|
+
osVersion = fetchOsVersion()
|
|
56
|
+
brand = fetchBrand()
|
|
57
|
+
manufacturer = fetchManufacturer()
|
|
58
|
+
model = fetchModel()
|
|
59
|
+
carrier = fetchCarrier()
|
|
60
|
+
country = fetchCountry()
|
|
61
|
+
language = fetchLanguage()
|
|
62
|
+
gpsEnabled = checkGPSEnabled()
|
|
63
|
+
appSetId = fetchAppSetId()
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Internal methods for getting raw information
|
|
68
|
+
*/
|
|
69
|
+
private fun fetchVersionName(): String? {
|
|
70
|
+
val packageInfo: PackageInfo
|
|
71
|
+
try {
|
|
72
|
+
packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)
|
|
73
|
+
return packageInfo.versionName
|
|
74
|
+
} catch (e: PackageManager.NameNotFoundException) {
|
|
75
|
+
} catch (e: Exception) {
|
|
76
|
+
}
|
|
77
|
+
return null
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
private fun fetchOsVersion(): String {
|
|
81
|
+
return Build.VERSION.RELEASE
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private fun fetchBrand(): String {
|
|
85
|
+
return Build.BRAND
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
private fun fetchManufacturer(): String {
|
|
89
|
+
return Build.MANUFACTURER
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private fun fetchModel(): String {
|
|
93
|
+
return Build.MODEL
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
private fun fetchCarrier(): String? {
|
|
97
|
+
try {
|
|
98
|
+
val manager = context
|
|
99
|
+
.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
|
|
100
|
+
return manager.networkOperatorName
|
|
101
|
+
} catch (e: Exception) {
|
|
102
|
+
// Failed to get network operator name from network
|
|
103
|
+
}
|
|
104
|
+
return null
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
private fun fetchCountry(): String? {
|
|
108
|
+
// This should not be called on the main thread.
|
|
109
|
+
|
|
110
|
+
// Prioritize reverse geocode, but until we have a result from that,
|
|
111
|
+
// we try to grab the country from the network, and finally the locale
|
|
112
|
+
var country = countryFromLocation
|
|
113
|
+
if (!country.isNullOrEmpty()) {
|
|
114
|
+
return country
|
|
115
|
+
}
|
|
116
|
+
country = countryFromNetwork
|
|
117
|
+
return if (!country.isNullOrEmpty()) {
|
|
118
|
+
country
|
|
119
|
+
} else countryFromLocale
|
|
120
|
+
} // Customized Android System without Google Play Service Installed// sometimes the location manager is unavailable// Bad lat / lon values can cause Geocoder to throw IllegalArgumentExceptions// failed to fetch geocoder// Failed to reverse geocode location
|
|
121
|
+
|
|
122
|
+
// Failed to reverse geocode location
|
|
123
|
+
private val countryFromLocation: String?
|
|
124
|
+
private get() {
|
|
125
|
+
if (!isLocationListening) {
|
|
126
|
+
return null
|
|
127
|
+
}
|
|
128
|
+
val recent = mostRecentLocation
|
|
129
|
+
if (recent != null) {
|
|
130
|
+
try {
|
|
131
|
+
if (Geocoder.isPresent()) {
|
|
132
|
+
val geocoder = geocoder
|
|
133
|
+
val addresses = geocoder.getFromLocation(
|
|
134
|
+
recent.latitude,
|
|
135
|
+
recent.longitude, 1
|
|
136
|
+
)
|
|
137
|
+
if (addresses != null) {
|
|
138
|
+
for (address in addresses) {
|
|
139
|
+
if (address != null) {
|
|
140
|
+
return address.countryCode
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
} catch (e: IOException) {
|
|
146
|
+
// Failed to reverse geocode location
|
|
147
|
+
} catch (e: NullPointerException) {
|
|
148
|
+
// Failed to reverse geocode location
|
|
149
|
+
} catch (e: NoSuchMethodError) {
|
|
150
|
+
// failed to fetch geocoder
|
|
151
|
+
} catch (e: IllegalArgumentException) {
|
|
152
|
+
// Bad lat / lon values can cause Geocoder to throw IllegalArgumentExceptions
|
|
153
|
+
} catch (e: IllegalStateException) {
|
|
154
|
+
// sometimes the location manager is unavailable
|
|
155
|
+
} catch (e: SecurityException) {
|
|
156
|
+
// Customized Android System without Google Play Service Installed
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return null
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Failed to get country from network
|
|
163
|
+
private val countryFromNetwork: String?
|
|
164
|
+
private get() {
|
|
165
|
+
try {
|
|
166
|
+
val manager = context
|
|
167
|
+
.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
|
|
168
|
+
if (manager.phoneType != TelephonyManager.PHONE_TYPE_CDMA) {
|
|
169
|
+
val country = manager.networkCountryIso
|
|
170
|
+
if (country != null) {
|
|
171
|
+
return country.toUpperCase(Locale.US)
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
} catch (e: Exception) {
|
|
175
|
+
// Failed to get country from network
|
|
176
|
+
}
|
|
177
|
+
return null
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
private val locale: Locale
|
|
181
|
+
private get() {
|
|
182
|
+
val configuration = Resources.getSystem().configuration
|
|
183
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
184
|
+
val localeList = configuration.locales
|
|
185
|
+
if (localeList.isEmpty) {
|
|
186
|
+
return Locale.getDefault()
|
|
187
|
+
} else {
|
|
188
|
+
return localeList.get(0)
|
|
189
|
+
}
|
|
190
|
+
} else {
|
|
191
|
+
return configuration.locale
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
private val countryFromLocale: String
|
|
196
|
+
private get() = locale.country
|
|
197
|
+
|
|
198
|
+
private fun fetchLanguage(): String {
|
|
199
|
+
return locale.language
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
private fun fetchAdvertisingId(): String {
|
|
203
|
+
// This should not be called on the main thread.
|
|
204
|
+
return if ("Amazon" == fetchManufacturer()) {
|
|
205
|
+
fetchAndCacheAmazonAdvertisingId
|
|
206
|
+
} else {
|
|
207
|
+
fetchAndCacheGoogleAdvertisingId
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
private fun fetchAppSetId(): String {
|
|
212
|
+
try {
|
|
213
|
+
val AppSet = Class
|
|
214
|
+
.forName("com.google.android.gms.appset.AppSet")
|
|
215
|
+
val getClient = AppSet.getMethod("getClient", Context::class.java)
|
|
216
|
+
val appSetIdClient = getClient.invoke(null, context)
|
|
217
|
+
val getAppSetIdInfo = appSetIdClient.javaClass.getMethod("getAppSetIdInfo")
|
|
218
|
+
val taskWithAppSetInfo = getAppSetIdInfo.invoke(appSetIdClient)
|
|
219
|
+
val Tasks = Class.forName("com.google.android.gms.tasks.Tasks")
|
|
220
|
+
val await =
|
|
221
|
+
Tasks.getMethod("await", Class.forName("com.google.android.gms.tasks.Task"))
|
|
222
|
+
val appSetInfo = await.invoke(null, taskWithAppSetInfo)
|
|
223
|
+
val getId = appSetInfo.javaClass.getMethod("getId")
|
|
224
|
+
appSetId = getId.invoke(appSetInfo) as String
|
|
225
|
+
} catch (e: ClassNotFoundException) {
|
|
226
|
+
LogcatLogger.logger
|
|
227
|
+
.warn("Google Play Services SDK not found for app set id!")
|
|
228
|
+
} catch (e: InvocationTargetException) {
|
|
229
|
+
LogcatLogger.logger.warn("Google Play Services not available for app set id")
|
|
230
|
+
} catch (e: Exception) {
|
|
231
|
+
LogcatLogger.logger.error(
|
|
232
|
+
"Encountered an error connecting to Google Play Services for app set id"
|
|
233
|
+
)
|
|
234
|
+
}
|
|
235
|
+
return appSetId
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
private val fetchAndCacheAmazonAdvertisingId: String
|
|
239
|
+
private get() {
|
|
240
|
+
val cr = context.contentResolver
|
|
241
|
+
limitAdTrackingEnabled = Secure.getInt(cr, SETTING_LIMIT_AD_TRACKING, 0) == 1
|
|
242
|
+
advertisingId = Secure.getString(cr, SETTING_ADVERTISING_ID)
|
|
243
|
+
return advertisingId
|
|
244
|
+
}
|
|
245
|
+
private val fetchAndCacheGoogleAdvertisingId: String
|
|
246
|
+
private get() {
|
|
247
|
+
try {
|
|
248
|
+
val AdvertisingIdClient = Class
|
|
249
|
+
.forName("com.google.android.gms.ads.identifier.AdvertisingIdClient")
|
|
250
|
+
val getAdvertisingInfo = AdvertisingIdClient.getMethod(
|
|
251
|
+
"getAdvertisingIdInfo",
|
|
252
|
+
Context::class.java
|
|
253
|
+
)
|
|
254
|
+
val advertisingInfo = getAdvertisingInfo.invoke(null, context)
|
|
255
|
+
val isLimitAdTrackingEnabled = advertisingInfo.javaClass.getMethod(
|
|
256
|
+
"isLimitAdTrackingEnabled"
|
|
257
|
+
)
|
|
258
|
+
val limitAdTrackingEnabled = isLimitAdTrackingEnabled
|
|
259
|
+
.invoke(advertisingInfo) as Boolean
|
|
260
|
+
this.limitAdTrackingEnabled =
|
|
261
|
+
limitAdTrackingEnabled != null && limitAdTrackingEnabled
|
|
262
|
+
val getId = advertisingInfo.javaClass.getMethod("getId")
|
|
263
|
+
advertisingId = getId.invoke(advertisingInfo) as String
|
|
264
|
+
} catch (e: ClassNotFoundException) {
|
|
265
|
+
LogcatLogger.logger
|
|
266
|
+
.warn("Google Play Services SDK not found for advertising id!")
|
|
267
|
+
} catch (e: InvocationTargetException) {
|
|
268
|
+
LogcatLogger.logger
|
|
269
|
+
.warn("Google Play Services not available for advertising id")
|
|
270
|
+
} catch (e: Exception) {
|
|
271
|
+
LogcatLogger.logger.error(
|
|
272
|
+
"Encountered an error connecting to Google Play Services for advertising id"
|
|
273
|
+
)
|
|
274
|
+
}
|
|
275
|
+
return advertisingId
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
private fun checkGPSEnabled(): Boolean {
|
|
279
|
+
// This should not be called on the main thread.
|
|
280
|
+
try {
|
|
281
|
+
val GPSUtil = Class
|
|
282
|
+
.forName("com.google.android.gms.common.GooglePlayServicesUtil")
|
|
283
|
+
val getGPSAvailable = GPSUtil.getMethod(
|
|
284
|
+
"isGooglePlayServicesAvailable",
|
|
285
|
+
Context::class.java
|
|
286
|
+
)
|
|
287
|
+
val status = getGPSAvailable.invoke(null, context) as Int
|
|
288
|
+
// status 0 corresponds to com.google.android.gms.common.ConnectionResult.SUCCESS;
|
|
289
|
+
return status != null && status == 0
|
|
290
|
+
} catch (e: NoClassDefFoundError) {
|
|
291
|
+
LogcatLogger.logger.warn("Google Play Services Util not found!")
|
|
292
|
+
} catch (e: ClassNotFoundException) {
|
|
293
|
+
LogcatLogger.logger.warn("Google Play Services Util not found!")
|
|
294
|
+
} catch (e: NoSuchMethodException) {
|
|
295
|
+
LogcatLogger.logger.warn("Google Play Services not available")
|
|
296
|
+
} catch (e: InvocationTargetException) {
|
|
297
|
+
LogcatLogger.logger.warn("Google Play Services not available")
|
|
298
|
+
} catch (e: IllegalAccessException) {
|
|
299
|
+
LogcatLogger.logger.warn("Google Play Services not available")
|
|
300
|
+
} catch (e: Exception) {
|
|
301
|
+
LogcatLogger.logger.warn(
|
|
302
|
+
"Error when checking for Google Play Services: $e"
|
|
303
|
+
)
|
|
304
|
+
}
|
|
305
|
+
return false
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
fun prefetch() {
|
|
310
|
+
cachedInfo
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
fun isGooglePlayServicesEnabled(): Boolean {
|
|
314
|
+
return cachedInfo!!.gpsEnabled
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
fun isLimitAdTrackingEnabled(): Boolean {
|
|
318
|
+
return cachedInfo!!.limitAdTrackingEnabled
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
val versionName: String?
|
|
322
|
+
get() = cachedInfo!!.versionName
|
|
323
|
+
val osName: String
|
|
324
|
+
get() = cachedInfo!!.osName
|
|
325
|
+
val osVersion: String
|
|
326
|
+
get() = cachedInfo!!.osVersion
|
|
327
|
+
val brand: String
|
|
328
|
+
get() = cachedInfo!!.brand
|
|
329
|
+
val manufacturer: String
|
|
330
|
+
get() = cachedInfo!!.manufacturer
|
|
331
|
+
val model: String
|
|
332
|
+
get() = cachedInfo!!.model
|
|
333
|
+
val carrier: String?
|
|
334
|
+
get() = cachedInfo!!.carrier
|
|
335
|
+
val country: String?
|
|
336
|
+
get() = cachedInfo!!.country
|
|
337
|
+
val language: String
|
|
338
|
+
get() = cachedInfo!!.language
|
|
339
|
+
val advertisingId: String
|
|
340
|
+
get() = cachedInfo!!.advertisingId
|
|
341
|
+
val appSetId: String
|
|
342
|
+
get() = cachedInfo!!.appSetId // other causes// failed to get providers list
|
|
343
|
+
// Don't crash if the device does not have location services.
|
|
344
|
+
|
|
345
|
+
// It's possible that the location service is running out of process
|
|
346
|
+
// and the remote getProviders call fails. Handle null provider lists.
|
|
347
|
+
val mostRecentLocation: Location?
|
|
348
|
+
get() {
|
|
349
|
+
if (!isLocationListening) {
|
|
350
|
+
return null
|
|
351
|
+
}
|
|
352
|
+
if (!Utils.checkLocationPermissionAllowed(context)) {
|
|
353
|
+
return null
|
|
354
|
+
}
|
|
355
|
+
val locationManager = context
|
|
356
|
+
.getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
|
357
|
+
?: return null
|
|
358
|
+
|
|
359
|
+
// Don't crash if the device does not have location services.
|
|
360
|
+
|
|
361
|
+
// It's possible that the location service is running out of process
|
|
362
|
+
// and the remote getProviders call fails. Handle null provider lists.
|
|
363
|
+
var providers: List<String?>? = null
|
|
364
|
+
try {
|
|
365
|
+
providers = locationManager.getProviders(true)
|
|
366
|
+
} catch (e: SecurityException) {
|
|
367
|
+
// failed to get providers list
|
|
368
|
+
} catch (e: Exception) {
|
|
369
|
+
// other causes
|
|
370
|
+
}
|
|
371
|
+
if (providers == null) {
|
|
372
|
+
return null
|
|
373
|
+
}
|
|
374
|
+
val locations: MutableList<Location> = ArrayList()
|
|
375
|
+
for (provider in providers) {
|
|
376
|
+
var location: Location? = null
|
|
377
|
+
try {
|
|
378
|
+
location = locationManager.getLastKnownLocation(provider!!)
|
|
379
|
+
} catch (e: SecurityException) {
|
|
380
|
+
LogcatLogger.logger.warn("Failed to get most recent location")
|
|
381
|
+
} catch (e: Exception) {
|
|
382
|
+
LogcatLogger.logger.warn("Failed to get most recent location")
|
|
383
|
+
}
|
|
384
|
+
if (location != null) {
|
|
385
|
+
locations.add(location)
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
var maximumTimestamp: Long = -1
|
|
389
|
+
var bestLocation: Location? = null
|
|
390
|
+
for (location in locations) {
|
|
391
|
+
if (location.time > maximumTimestamp) {
|
|
392
|
+
maximumTimestamp = location.time
|
|
393
|
+
bestLocation = location
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
return bestLocation
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// @VisibleForTesting
|
|
400
|
+
protected val geocoder: Geocoder
|
|
401
|
+
protected get() = Geocoder(context, Locale.ENGLISH)
|
|
402
|
+
|
|
403
|
+
companion object {
|
|
404
|
+
const val OS_NAME = "android"
|
|
405
|
+
const val SETTING_LIMIT_AD_TRACKING = "limit_ad_tracking"
|
|
406
|
+
const val SETTING_ADVERTISING_ID = "advertising_id"
|
|
407
|
+
fun generateUUID(): String {
|
|
408
|
+
return UUID.randomUUID().toString()
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
init {
|
|
413
|
+
isLocationListening = locationListening
|
|
414
|
+
}
|
|
415
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
package com.amplitude.reactnative
|
|
2
|
+
|
|
3
|
+
import android.util.Log
|
|
4
|
+
|
|
5
|
+
interface Logger {
|
|
6
|
+
enum class LogMode(i: Int) {
|
|
7
|
+
DEBUG(1),
|
|
8
|
+
INFO(2),
|
|
9
|
+
WARN(3),
|
|
10
|
+
ERROR(4),
|
|
11
|
+
OFF(5)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
var logMode: LogMode
|
|
15
|
+
|
|
16
|
+
fun debug(message: String)
|
|
17
|
+
|
|
18
|
+
fun error(message: String)
|
|
19
|
+
|
|
20
|
+
fun info(message: String)
|
|
21
|
+
|
|
22
|
+
fun warn(message: String)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
class LogcatLogger() : Logger {
|
|
26
|
+
override var logMode: Logger.LogMode = Logger.LogMode.INFO
|
|
27
|
+
private val tag = "Amplitude"
|
|
28
|
+
|
|
29
|
+
override fun debug(message: String) {
|
|
30
|
+
if (logMode <= Logger.LogMode.DEBUG) {
|
|
31
|
+
Log.d(tag, message)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
override fun error(message: String) {
|
|
36
|
+
if (logMode <= Logger.LogMode.ERROR) {
|
|
37
|
+
Log.e(tag, message)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
override fun info(message: String) {
|
|
42
|
+
if (logMode <= Logger.LogMode.INFO) {
|
|
43
|
+
Log.i(tag, message)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
override fun warn(message: String) {
|
|
48
|
+
if (logMode <= Logger.LogMode.WARN) {
|
|
49
|
+
Log.w(tag, message)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
companion object {
|
|
54
|
+
val logger = LogcatLogger()
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
package com.amplitude.reactnative
|
|
2
|
+
|
|
3
|
+
import android.Manifest
|
|
4
|
+
import android.app.Activity
|
|
5
|
+
import android.content.Context
|
|
6
|
+
import android.content.pm.PackageManager
|
|
7
|
+
import android.os.Build
|
|
8
|
+
|
|
9
|
+
object Utils {
|
|
10
|
+
|
|
11
|
+
fun checkLocationPermissionAllowed(context: Context?): Boolean {
|
|
12
|
+
return checkPermissionAllowed(context, Manifest.permission.ACCESS_COARSE_LOCATION) ||
|
|
13
|
+
checkPermissionAllowed(context, Manifest.permission.ACCESS_FINE_LOCATION)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
fun checkPermissionAllowed(context: Context?, permission: String?): Boolean {
|
|
17
|
+
// ANDROID 6.0 AND UP!
|
|
18
|
+
return if (Build.VERSION.SDK_INT >= 23) {
|
|
19
|
+
var hasPermission = false
|
|
20
|
+
try {
|
|
21
|
+
// Invoke checkSelfPermission method from Android 6 (API 23 and UP)
|
|
22
|
+
val methodCheckPermission =
|
|
23
|
+
Activity::class.java.getMethod("checkSelfPermission", String::class.java)
|
|
24
|
+
val resultObj = methodCheckPermission.invoke(context, permission)
|
|
25
|
+
val result = resultObj.toString().toInt()
|
|
26
|
+
hasPermission = result == PackageManager.PERMISSION_GRANTED
|
|
27
|
+
} catch (ex: Exception) {
|
|
28
|
+
}
|
|
29
|
+
hasPermission
|
|
30
|
+
} else {
|
|
31
|
+
true
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|