Skip to content

Commit

Permalink
fix: update gradle files for 0.73 support (#917)
Browse files Browse the repository at this point in the history
* fix: update gradle files for 0.73 support

Current lib should just work with 0.73 but taking preliminary steps to keep up to date based on the work specified [here](react-native-community/discussions-and-proposals#671)
And in particular on the revised outputs of [create-react-native-library CLI](https://github.com/callstack/react-native-builder-bob/blob/fc8744092501ba00fd11bdb69e1ecb46fbb63c0f/packages/create-react-native-library/templates/native-common/android/build.gradle)

- Updated build.gradle and gradle.properties to match new CLI outputs
- Added new AndroidManifest.xml without namespace
- Added namespace in build.gradle only if Gradle 7.3+

* fix: refactor deep compare

- Refactor deepCompare as a utility from the core. We might want to add this feature in `identify` in the future. 
- Refactor to pass Typescript linter
- Refactor to fix gaps with previous implementation: `old` might have more properties than `new`
- Added tests
  • Loading branch information
oscb committed Feb 12, 2024
1 parent 285a3bd commit 98d5b05
Show file tree
Hide file tree
Showing 13 changed files with 307 additions and 286 deletions.
133 changes: 48 additions & 85 deletions packages/core/android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,40 +1,63 @@
buildscript {
// Buildscript is evaluated before everything else so we can't use getExtOrDefault
def kotlin_version = rootProject.ext.has('kotlinVersion') ? rootProject.ext.get('kotlinVersion') : project.properties['AnalyticsReactNative_kotlinVersion']
def kotlin_version = rootProject.ext.has("kotlinVersion") ? rootProject.ext.get("kotlinVersion") : project.properties["AnalyticsReactNative_kotlinVersion"]

repositories {
google()
jcenter()
mavenCentral()
}

dependencies {
classpath 'com.android.tools.build:gradle:4.0.1'
classpath "com.android.tools.build:gradle:7.2.1"
// noinspection DifferentKotlinGradleVersion
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}

apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
def isNewArchitectureEnabled() {
return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
}

apply plugin: "com.android.library"
apply plugin: "kotlin-android"

if (isNewArchitectureEnabled()) {
apply plugin: "com.facebook.react"
}

def getExtOrDefault(name) {
return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['AnalyticsReactNative_' + name]
return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["AnalyticsReactNative_" + name]
}

def getExtOrIntegerDefault(name) {
return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties['AnalyticsReactNative_' + name]).toInteger()
return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["AnalyticsReactNative_" + name]).toInteger()
}

def supportsNamespace() {
def parsed = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.')
def major = parsed[0].toInteger()
def minor = parsed[1].toInteger()

// Namespace support was added in 7.3.0
return (major == 7 && minor >= 3) || major >= 8
}

android {
compileSdkVersion getExtOrIntegerDefault('compileSdkVersion')
buildToolsVersion getExtOrDefault('buildToolsVersion')
if (supportsNamespace()) {
namespace "com.segmentanalyticsreactnative"

sourceSets {
main {
manifest.srcFile "src/main/AndroidManifestNew.xml"
}
}
}

compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")

defaultConfig {
minSdkVersion 21
targetSdkVersion getExtOrIntegerDefault('targetSdkVersion')
compileSdkVersion = getExtOrIntegerDefault('compileSdkVersion')
versionCode 1
versionName "1.0"
minSdkVersion getExtOrIntegerDefault("minSdkVersion")
targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")

}

Expand All @@ -43,9 +66,11 @@ android {
minifyEnabled false
}
}

lintOptions {
disable 'GradleCompatible'
disable "GradleCompatible"
}

compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
Expand All @@ -54,80 +79,18 @@ android {

repositories {
mavenCentral()
jcenter()
google()

def found = false
def defaultDir = null
def androidSourcesName = 'React Native sources'

if (rootProject.ext.has('reactNativeAndroidRoot')) {
defaultDir = rootProject.ext.get('reactNativeAndroidRoot')
} else {
defaultDir = new File(
projectDir,
'/../../../node_modules/react-native/android'
)
}

if (defaultDir.exists()) {
maven {
url defaultDir.toString()
name androidSourcesName
}

logger.info(":${project.name}:reactNativeAndroidRoot ${defaultDir.canonicalPath}")
found = true
} else {
def parentDir = rootProject.projectDir

1.upto(5, {
if (found) return true
parentDir = parentDir.parentFile

def androidSourcesDir = new File(
parentDir,
'node_modules/react-native'
)

def androidPrebuiltBinaryDir = new File(
parentDir,
'node_modules/react-native/android'
)

if (androidPrebuiltBinaryDir.exists()) {
maven {
url androidPrebuiltBinaryDir.toString()
name androidSourcesName
}

logger.info(":${project.name}:reactNativeAndroidRoot ${androidPrebuiltBinaryDir.canonicalPath}")
found = true
} else if (androidSourcesDir.exists()) {
maven {
url androidSourcesDir.toString()
name androidSourcesName
}

logger.info(":${project.name}:reactNativeAndroidRoot ${androidSourcesDir.canonicalPath}")
found = true
}
})
}

if (!found) {
throw new GradleException(
"${project.name}: unable to locate React Native android sources. " +
"Ensure you have you installed React Native as a dependency in your project and try again."
)
}
}

def kotlin_version = getExtOrDefault('kotlinVersion')
def kotlin_version = getExtOrDefault("kotlinVersion")

dependencies {
// noinspection GradleDynamicVersion
api 'com.facebook.react:react-native:+'
// For < 0.71, this will be from the local maven repo
// For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin
//noinspection GradleDynamicVersion
implementation "com.facebook.react:react-native:+"
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation project(path: ':segment_sovran-react-native')
// Requires sovran for communication
implementation project(path: ':segment_sovran-react-native')
}

7 changes: 4 additions & 3 deletions packages/core/android/gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
AnalyticsReactNative_kotlinVersion=1.7.0
AnalyticsReactNative_compileSdkVersion=29
AnalyticsReactNative_buildToolsVersion=29.0.2
AnalyticsReactNative_targetSdkVersion=29
AnalyticsReactNative_minSdkVersion=21
AnalyticsReactNative_targetSdkVersion=31
AnalyticsReactNative_compileSdkVersion=31
AnalyticsReactNative_ndkversion=21.4.7075529
3 changes: 3 additions & 0 deletions packages/core/android/src/main/AndroidManifestNew.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest>
99 changes: 98 additions & 1 deletion packages/core/src/__tests__/util.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { chunk, allSettled } from '../util';
import { UserTraits } from '../types';
import { chunk, allSettled, deepCompare } from '../util';

describe('#chunk', () => {
it('handles empty array', () => {
Expand Down Expand Up @@ -62,3 +63,99 @@ describe('allSettled', () => {
]);
});
});

describe('deepCompare', () => {
const base: UserTraits = {
age: 30,
address: {
city: 'San Francisco',
country: 'USA',
},
company: {
name: 'Twilio',
},
deepNested: {
level1: {
level2: {
level3: true,
},
},
},
};

it('shallow compare, same object should return true', () => {
const a: UserTraits = { ...base };
const b: UserTraits = a;
expect(deepCompare(a, b)).toBe(true);
});

it('deep compare, object copy should return true', () => {
const a: UserTraits = { ...base };
const b: UserTraits = { ...base };
expect(deepCompare(a, b)).toBe(true);
});

it('deep compare, different key objects should return false', () => {
const a: UserTraits = { ...base };
const b: UserTraits = {
age: 20,
deepNested: {
level1: {
level2: {
level3: false,
},
},
},
};
expect(deepCompare(a, b)).toBe(false);
});

it('deep compare, modified objects should return false', () => {
const a: UserTraits = { ...base };
const b: UserTraits = {
...base,
age: 20,
deepNested: {
level1: {
level2: {
level3: false,
},
},
},
};
expect(deepCompare(a, b)).toBe(false);
});

it('deep compare, different nested objects should return false', () => {
const a: UserTraits = { ...base };
const b: UserTraits = {
...base,
age: 20,
deepNested: {
level1: {
level2: {
level3: true,
},
anotherLevel2: {
level3: true,
},
},
},
};
expect(deepCompare(a, b)).toBe(false);
});

it('deep compare, mistmatching nested object type should return false', () => {
const a: UserTraits = { ...base };
const b: UserTraits = {
...base,
age: 20,
deepNested: {
level1: {
level2: 1,
},
},
};
expect(deepCompare(a, b)).toBe(false);
});
});
1 change: 1 addition & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export {
isDate,
objectToString,
unknownToString,
deepCompare,
} from './util';
export { SegmentClient } from './analytics';
export { SegmentDestination } from './plugins/SegmentDestination';
Expand Down
40 changes: 37 additions & 3 deletions packages/core/src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const sizeOf = (obj: unknown): number => {

export const warnMissingNativeModule = () => {
const MISSING_NATIVE_MODULE_WARNING =
`The package 'analytics-react-native' can't access a custom native module. Make sure: \n\n` +
"The package 'analytics-react-native' can't access a custom native module. Make sure: \n\n" +
Platform.select({ ios: "- You have run 'pod install'\n", default: '' }) +
'- You rebuilt the app after installing the package\n' +
'- You are not using Expo managed workflow\n';
Expand All @@ -18,7 +18,9 @@ export const warnMissingNativeModule = () => {

export const getNativeModule = (moduleName: string) => {
const module = (NativeModules[moduleName] as NativeModule) ?? undefined;
if (module === undefined) warnMissingNativeModule();
if (module === undefined) {
warnMissingNativeModule();
}
return module;
};

Expand Down Expand Up @@ -143,7 +145,6 @@ export function isDate(value: unknown): value is Date {
export function objectToString(value: object, json = true): string | undefined {
// If the object has a custom toString we well use that
if (value.toString !== Object.prototype.toString) {
// eslint-disable-next-line @typescript-eslint/no-base-to-string
return value.toString();
}
if (json) {
Expand Down Expand Up @@ -198,3 +199,36 @@ export const isObject = (value: unknown): value is Record<string, unknown> =>
value !== undefined &&
typeof value === 'object' &&
!Array.isArray(value);

/**
* Utility to deeply compare 2 objects
* @param a unknown object
* @param b unknown object
* @returns true if both objects have the same keys and values
*/
export function deepCompare<T>(a: T, b: T): boolean {
// Shallow compare first, just in case
if (a === b) {
return true;
}

// If not objects then compare values directly
if (!isObject(a) || !isObject(b)) {
return a === b;
}

const keysA = Object.keys(a);
const keysB = Object.keys(b);

if (keysA.length !== keysB.length) {
return false;
}

for (const key of keysA) {
if (!keysB.includes(key) || !deepCompare(a[key], b[key])) {
return false;
}
}

return true;
}
Loading

0 comments on commit 98d5b05

Please sign in to comment.