diff --git a/packages/react-native-cli/src/lib/Gradle.ts b/packages/react-native-cli/src/lib/Gradle.ts index ea68a170ac..daddbe8b16 100644 --- a/packages/react-native-cli/src/lib/Gradle.ts +++ b/packages/react-native-cli/src/lib/Gradle.ts @@ -1,6 +1,8 @@ import { Logger } from '../Logger' import { promises as fs } from 'fs' import path from 'path' +import { detectInstalledVersion } from './Npm' +import semver from 'semver' const GRADLE_PLUGIN_IMPORT = (version: string) => `classpath("com.bugsnag:bugsnag-android-gradle-plugin:${version}")` const GRADLE_PLUGIN_IMPORT_REGEX = /classpath\(["']com\.bugsnag:bugsnag-android-gradle-plugin:.*["']\)/ @@ -12,6 +14,9 @@ const BUGSNAG_CONFIGURATION_BLOCK = 'bugsnag {\n}\n' const BUGSNAG_CONFIGURATION_BLOCK_REGEX = /^\s*bugsnag {[^}]*?}/m const UPLOAD_ENDPOINT_REGEX = /^\s*bugsnag {[^}]*endpoint[^}]*?}/m const BUILD_ENDPOINT_REGEX = /^\s*bugsnag {[^}]*releasesEndpoint[^}]*?}/m +const GRADLE_VERSION_FAIL_MSG = `Cannot determine an appropriate version of the Bugsnag Android Gradle plugin for use in this project. + +Please see ${DOCS_LINK} for information on Gradle and the Android Gradle Plugin (AGP) compatibility` export async function getSuggestedBugsnagGradleVersion (projectRoot: string, logger: Logger): Promise { let fileContents: string @@ -30,14 +35,24 @@ export async function getSuggestedBugsnagGradleVersion (projectRoot: string, log } else if (major === 7) { return '7.+' } else { - const versionMatchResult = fileContents.match(/classpath\(["']com.android.tools.build:gradle["']\)/) - if (versionMatchResult) { + // if the AGP version isn't set explicitly in the build.gradle file, + // try to suggest a version based on the detected react-native version + const noVersionMatchResult = fileContents.match(/classpath\(["']com.android.tools.build:gradle["']\)/) + let reactNativeVersion + try { + reactNativeVersion = await detectInstalledVersion('react-native', projectRoot) + } catch (e) {} + + if (!noVersionMatchResult || !reactNativeVersion) { + logger.warn(GRADLE_VERSION_FAIL_MSG) + return '' + } + + // RN 0.73+ requires AGP 8.+ + if (semver.lt(reactNativeVersion, '0.73.0')) { return '7.+' } else { - logger.warn(`Cannot determine an appropriate version of the Bugsnag Android Gradle plugin for use in this project. - -Please see ${DOCS_LINK} for information on Gradle and the Android Gradle Plugin (AGP) compatibility`) - return '' + return '8.+' } } } diff --git a/packages/react-native-cli/src/lib/Insert.ts b/packages/react-native-cli/src/lib/Insert.ts index 7e95c392ce..31b01d3f55 100644 --- a/packages/react-native-cli/src/lib/Insert.ts +++ b/packages/react-native-cli/src/lib/Insert.ts @@ -18,6 +18,10 @@ const BUGSNAG_JAVA_IMPORT = 'import com.bugsnag.android.Bugsnag;' const BUGSNAG_JAVA_INIT = 'Bugsnag.start(this);' const JAVA_APP_ON_CREATE_REGEX = /(public void onCreate\s*\(\)\s*\{[^]*super\.onCreate\(\);(\s*))\S/ +const BUGSNAG_KOTLIN_IMPORT = 'import com.bugsnag.android.Bugsnag' +const BUGSNAG_KOTLIN_INIT = 'Bugsnag.start(this)' +const KOTLIN_APP_ON_CREATE_REGEX = /(override fun onCreate\s*\(\)\s*\{[^]*super\.onCreate\(\)(\s*))\S/ + const DOCS_LINK = 'https://docs.bugsnag.com/platforms/react-native/react-native/#basic-configuration' const FAIL_MSG = (filename: string) => `Failed to update "${filename}" automatically. The file may not exist or it may be in an unexpected format or location. @@ -114,39 +118,39 @@ export async function insertAndroid (projectRoot: string, logger: Logger): Promi cwd: javaDir }))[0] - const relativeMainApplicationPathOther = (await asyncGlob('**/*/MainApplication', { - cwd: javaDir - }))[0] - - const relativeMainApplicationPath = relativeMainApplicationPathJava || relativeMainApplicationPathKotlin || relativeMainApplicationPathOther + const relativeMainApplicationPath = relativeMainApplicationPathJava || relativeMainApplicationPathKotlin if (!relativeMainApplicationPath) { - return logger.warn(FAIL_MSG('MainApplication.java, MainApplication.kt or MainApplication')) + return logger.warn(FAIL_MSG('MainApplication')) } mainApplicationPath = path.join(javaDir, relativeMainApplicationPath) } catch (e) { - logger.warn(FAIL_MSG('MainApplication.java, MainApplication.kt or MainApplication')) + logger.warn(FAIL_MSG('MainApplication')) return } try { - const mainApplication = await fs.readFile(mainApplicationPath, 'utf8') + const isKotlin = path.extname(mainApplicationPath) === '.kt' + const bugsnagImport = isKotlin ? BUGSNAG_KOTLIN_IMPORT : BUGSNAG_JAVA_IMPORT + const bugsnagInit = isKotlin ? BUGSNAG_KOTLIN_INIT : BUGSNAG_JAVA_INIT + const onCreateRegex = isKotlin ? KOTLIN_APP_ON_CREATE_REGEX : JAVA_APP_ON_CREATE_REGEX - if (mainApplication.includes(BUGSNAG_JAVA_IMPORT) || mainApplication.includes(BUGSNAG_JAVA_INIT)) { + const mainApplication = await fs.readFile(mainApplicationPath, 'utf8') + if (mainApplication.includes(bugsnagImport) || mainApplication.includes(bugsnagInit)) { logger.warn('Bugsnag is already included, skipping') return } - const mainApplicationWithImport = mainApplication.replace('import', `${BUGSNAG_JAVA_IMPORT}\nimport`) - const onCreateRes = JAVA_APP_ON_CREATE_REGEX.exec(mainApplicationWithImport) + const mainApplicationWithImport = mainApplication.replace('import', `${bugsnagImport}\nimport`) + const onCreateRes = onCreateRegex.exec(mainApplicationWithImport) if (!onCreateRes) { - logger.warn(FAIL_MSG('MainApplication.java, MainApplication.kt or MainApplication')) + logger.warn(FAIL_MSG('MainApplication')) return } - await fs.writeFile(mainApplicationPath, mainApplicationWithImport.replace(onCreateRes[1], `${onCreateRes[1]}${BUGSNAG_JAVA_INIT}${onCreateRes[2]}`), 'utf8') + await fs.writeFile(mainApplicationPath, mainApplicationWithImport.replace(onCreateRes[1], `${onCreateRes[1]}${bugsnagInit}${onCreateRes[2]}`), 'utf8') logger.success('Done') } catch (e) { - logger.error(FAIL_MSG('MainApplication.java, MainApplication.kt or MainApplication')) + logger.error(FAIL_MSG('MainApplication')) } } diff --git a/packages/react-native-cli/src/lib/__test__/Gradle.test.ts b/packages/react-native-cli/src/lib/__test__/Gradle.test.ts index e6092f17b7..b024323340 100644 --- a/packages/react-native-cli/src/lib/__test__/Gradle.test.ts +++ b/packages/react-native-cli/src/lib/__test__/Gradle.test.ts @@ -512,3 +512,31 @@ test('getSuggestedBugsnagGradleVersion(): success with bracketed AGP version', a const version = await getSuggestedBugsnagGradleVersion('/random/path', logger) expect(version).toBe('7.+') }) + +test('getSuggestedBugsnagGradleVersion(): success with unspecified AGP version', async () => { + const buildGradle = await loadFixture(path.join(__dirname, 'fixtures', 'root-build-before-without-agp-version.gradle')) + + const readFileMock = fs.readFile as jest.MockedFunction + readFileMock.mockResolvedValueOnce(buildGradle) + readFileMock.mockResolvedValueOnce('{"dependencies": { "react-native": "0.73.0"} }') + + let version = await getSuggestedBugsnagGradleVersion('/random/path', logger) + expect(version).toBe('8.+') + + readFileMock.mockResolvedValueOnce(buildGradle) + readFileMock.mockResolvedValueOnce('{"dependencies": { "react-native": "0.72.11"} }') + + version = await getSuggestedBugsnagGradleVersion('/random/path', logger) + expect(version).toBe('7.+') +}) + +test('getSuggestedBugsnagGradleVersion(): null with unspecified AGP and react native versions', async () => { + const buildGradle = await loadFixture(path.join(__dirname, 'fixtures', 'root-build-before-without-agp-version.gradle')) + + const readFileMock = fs.readFile as jest.MockedFunction + readFileMock.mockResolvedValueOnce(buildGradle) + readFileMock.mockResolvedValueOnce('') + + const version = await getSuggestedBugsnagGradleVersion('/random/path', logger) + expect(version).toBe('') +}) diff --git a/packages/react-native-cli/src/lib/__test__/Insert.test.ts b/packages/react-native-cli/src/lib/__test__/Insert.test.ts index c7d69ab6aa..e128d797b0 100644 --- a/packages/react-native-cli/src/lib/__test__/Insert.test.ts +++ b/packages/react-native-cli/src/lib/__test__/Insert.test.ts @@ -185,7 +185,7 @@ test('insertIos(): no identifiable app launch method', async () => { expect(logger.warn).toHaveBeenCalledWith(expect.stringContaining('Failed to update "AppDelegate.mm" automatically.')) }) -test('insertAndroid(): success', async () => { +test('insertAndroid(): success (java)', async () => { const globMock = glob as unknown as jest.MockedFunction globMock.mockImplementation((glob, opts, cb) => cb(null, ['com/bugsnagreactnativeclitest/MainApplication.java'])) @@ -207,7 +207,29 @@ test('insertAndroid(): success', async () => { ) }) -test('insertAndroid(): success, tolerates some differences in source', async () => { +test('insertAndroid(): success (kotlin)', async () => { + const globMock = glob as unknown as jest.MockedFunction + globMock.mockImplementation((glob, opts, cb) => cb(null, ['com/bugsnagreactnativeclitest/MainApplication.kt'])) + + const mainApplication = await loadFixture(path.join(__dirname, 'fixtures', 'MainApplication-before.kt')) + const readFileMock = fs.readFile as jest.MockedFunction + readFileMock.mockResolvedValue(mainApplication) + + const writeFileMock = fs.writeFile as jest.MockedFunction + + await insertAndroid('/random/path', logger) + expect(readFileMock).toHaveBeenCalledWith( + '/random/path/android/app/src/main/java/com/bugsnagreactnativeclitest/MainApplication.kt', + 'utf8' + ) + expect(writeFileMock).toHaveBeenCalledWith( + '/random/path/android/app/src/main/java/com/bugsnagreactnativeclitest/MainApplication.kt', + await loadFixture(path.join(__dirname, 'fixtures', 'MainApplication-after.kt')), + 'utf8' + ) +}) + +test('insertAndroid(): success, tolerates some differences in source (java)', async () => { const globMock = glob as unknown as jest.MockedFunction globMock.mockImplementation((glob, opts, cb) => cb(null, ['com/bugsnagreactnativeclitest/MainApplication.java'])) @@ -229,7 +251,29 @@ test('insertAndroid(): success, tolerates some differences in source', async () ) }) -test('insertAndroid(): already present', async () => { +test('insertAndroid(): success, tolerates some differences in source (kotlin)', async () => { + const globMock = glob as unknown as jest.MockedFunction + globMock.mockImplementation((glob, opts, cb) => cb(null, ['com/bugsnagreactnativeclitest/MainApplication.kt'])) + + const mainApplication = await loadFixture(path.join(__dirname, 'fixtures', 'MainApplication-before-2.kt')) + const readFileMock = fs.readFile as jest.MockedFunction + readFileMock.mockResolvedValue(mainApplication) + + const writeFileMock = fs.writeFile as jest.MockedFunction + + await insertAndroid('/random/path', logger) + expect(readFileMock).toHaveBeenCalledWith( + '/random/path/android/app/src/main/java/com/bugsnagreactnativeclitest/MainApplication.kt', + 'utf8' + ) + expect(writeFileMock).toHaveBeenCalledWith( + '/random/path/android/app/src/main/java/com/bugsnagreactnativeclitest/MainApplication.kt', + await loadFixture(path.join(__dirname, 'fixtures', 'MainApplication-after-2.kt')), + 'utf8' + ) +}) + +test('insertAndroid(): already present (java)', async () => { const globMock = glob as unknown as jest.MockedFunction globMock.mockImplementation((glob, opts, cb) => cb(null, ['com/bugsnagreactnativeclitest/MainApplication.java'])) @@ -249,6 +293,26 @@ test('insertAndroid(): already present', async () => { expect(logger.warn).toHaveBeenCalledWith('Bugsnag is already included, skipping') }) +test('insertAndroid(): already present (kotlin)', async () => { + const globMock = glob as unknown as jest.MockedFunction + globMock.mockImplementation((glob, opts, cb) => cb(null, ['com/bugsnagreactnativeclitest/MainApplication.kt'])) + + const mainApplication = await loadFixture(path.join(__dirname, 'fixtures', 'MainApplication-after.kt')) + const readFileMock = fs.readFile as jest.MockedFunction + readFileMock.mockResolvedValue(mainApplication) + + const writeFileMock = fs.writeFile as jest.MockedFunction + + await insertAndroid('/random/path', logger) + expect(readFileMock).toHaveBeenCalledWith( + '/random/path/android/app/src/main/java/com/bugsnagreactnativeclitest/MainApplication.kt', + 'utf8' + ) + expect(writeFileMock).not.toHaveBeenCalled() + + expect(logger.warn).toHaveBeenCalledWith('Bugsnag is already included, skipping') +}) + test('insertAndroid(): failure to locate file', async () => { const globMock = glob as unknown as jest.MockedFunction globMock.mockImplementation((glob, opts, cb) => cb(null, ['com/bugsnagreactnativeclitest/MainApplication.java'])) @@ -265,7 +329,7 @@ test('insertAndroid(): failure to locate file', async () => { ) expect(writeFileMock).not.toHaveBeenCalled() - expect(logger.error).toHaveBeenCalledWith(expect.stringContaining('Failed to update "MainApplication.java, MainApplication.kt or MainApplication" automatically.')) + expect(logger.error).toHaveBeenCalledWith(expect.stringContaining('Failed to update "MainApplication" automatically.')) }) test('insertAndroid(): failure to locate package directory', async () => { @@ -279,7 +343,7 @@ test('insertAndroid(): failure to locate package directory', async () => { expect(readFileMock).not.toHaveBeenCalled() expect(writeFileMock).not.toHaveBeenCalled() - expect(logger.warn).toHaveBeenCalledWith(expect.stringContaining('Failed to update "MainApplication.java, MainApplication.kt or MainApplication" automatically.')) + expect(logger.warn).toHaveBeenCalledWith(expect.stringContaining('Failed to update "MainApplication" automatically.')) }) test('insertAndroid(): project directory error', async () => { @@ -293,7 +357,7 @@ test('insertAndroid(): project directory error', async () => { expect(readFileMock).not.toHaveBeenCalled() expect(writeFileMock).not.toHaveBeenCalled() - expect(logger.warn).toHaveBeenCalledWith(expect.stringContaining('Failed to update "MainApplication.java, MainApplication.kt or MainApplication" automatically.')) + expect(logger.warn).toHaveBeenCalledWith(expect.stringContaining('Failed to update "MainApplication" automatically.')) }) test('insertAndroid(): no identifiable onCreate method', async () => { @@ -311,5 +375,5 @@ test('insertAndroid(): no identifiable onCreate method', async () => { ) expect(writeFileMock).not.toHaveBeenCalled() - expect(logger.warn).toHaveBeenCalledWith(expect.stringContaining('Failed to update "MainApplication.java, MainApplication.kt or MainApplication" automatically.')) + expect(logger.warn).toHaveBeenCalledWith(expect.stringContaining('Failed to update "MainApplication" automatically.')) }) diff --git a/packages/react-native-cli/src/lib/__test__/fixtures/MainApplication-after-2.kt b/packages/react-native-cli/src/lib/__test__/fixtures/MainApplication-after-2.kt new file mode 100644 index 0000000000..873c8130e8 --- /dev/null +++ b/packages/react-native-cli/src/lib/__test__/fixtures/MainApplication-after-2.kt @@ -0,0 +1,48 @@ +package com.bugsnagreactnativeclitest + +import com.bugsnag.android.Bugsnag +import android.app.Application +import com.facebook.react.PackageList +import com.facebook.react.ReactApplication +import com.facebook.react.ReactHost +import com.facebook.react.ReactNativeHost +import com.facebook.react.ReactPackage +import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load +import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost +import com.facebook.react.defaults.DefaultReactNativeHost +import com.facebook.react.flipper.ReactNativeFlipper +import com.facebook.soloader.SoLoader + +class MainApplication : Application(), ReactApplication { + + override val reactNativeHost: ReactNativeHost = + object : DefaultReactNativeHost(this) { + override fun getPackages(): List = + PackageList(this).packages.apply { + // Packages that cannot be autolinked yet can be added manually here, for example: + // add(MyReactNativePackage()) + } + + override fun getJSMainModuleName(): String = "index" + + override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG + + override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED + override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED + } + + override val reactHost: ReactHost + get() = getDefaultReactHost(this.applicationContext, reactNativeHost) + + override fun onCreate() { + // something between curly brace and super call + super.onCreate() + Bugsnag.start(this) + SoLoader.init(this, false) + if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { + // If you opted-in for the New Architecture, we load the native entry point for this app. + load() + } + ReactNativeFlipper.initializeFlipper(this, reactNativeHost.reactInstanceManager) + } +} diff --git a/packages/react-native-cli/src/lib/__test__/fixtures/MainApplication-after.kt b/packages/react-native-cli/src/lib/__test__/fixtures/MainApplication-after.kt new file mode 100644 index 0000000000..67c3edb782 --- /dev/null +++ b/packages/react-native-cli/src/lib/__test__/fixtures/MainApplication-after.kt @@ -0,0 +1,47 @@ +package com.bugsnagreactnativeclitest + +import com.bugsnag.android.Bugsnag +import android.app.Application +import com.facebook.react.PackageList +import com.facebook.react.ReactApplication +import com.facebook.react.ReactHost +import com.facebook.react.ReactNativeHost +import com.facebook.react.ReactPackage +import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load +import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost +import com.facebook.react.defaults.DefaultReactNativeHost +import com.facebook.react.flipper.ReactNativeFlipper +import com.facebook.soloader.SoLoader + +class MainApplication : Application(), ReactApplication { + + override val reactNativeHost: ReactNativeHost = + object : DefaultReactNativeHost(this) { + override fun getPackages(): List = + PackageList(this).packages.apply { + // Packages that cannot be autolinked yet can be added manually here, for example: + // add(MyReactNativePackage()) + } + + override fun getJSMainModuleName(): String = "index" + + override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG + + override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED + override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED + } + + override val reactHost: ReactHost + get() = getDefaultReactHost(this.applicationContext, reactNativeHost) + + override fun onCreate() { + super.onCreate() + Bugsnag.start(this) + SoLoader.init(this, false) + if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { + // If you opted-in for the New Architecture, we load the native entry point for this app. + load() + } + ReactNativeFlipper.initializeFlipper(this, reactNativeHost.reactInstanceManager) + } +} diff --git a/packages/react-native-cli/src/lib/__test__/fixtures/MainApplication-before-2.kt b/packages/react-native-cli/src/lib/__test__/fixtures/MainApplication-before-2.kt new file mode 100644 index 0000000000..52b7349533 --- /dev/null +++ b/packages/react-native-cli/src/lib/__test__/fixtures/MainApplication-before-2.kt @@ -0,0 +1,46 @@ +package com.bugsnagreactnativeclitest + +import android.app.Application +import com.facebook.react.PackageList +import com.facebook.react.ReactApplication +import com.facebook.react.ReactHost +import com.facebook.react.ReactNativeHost +import com.facebook.react.ReactPackage +import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load +import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost +import com.facebook.react.defaults.DefaultReactNativeHost +import com.facebook.react.flipper.ReactNativeFlipper +import com.facebook.soloader.SoLoader + +class MainApplication : Application(), ReactApplication { + + override val reactNativeHost: ReactNativeHost = + object : DefaultReactNativeHost(this) { + override fun getPackages(): List = + PackageList(this).packages.apply { + // Packages that cannot be autolinked yet can be added manually here, for example: + // add(MyReactNativePackage()) + } + + override fun getJSMainModuleName(): String = "index" + + override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG + + override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED + override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED + } + + override val reactHost: ReactHost + get() = getDefaultReactHost(this.applicationContext, reactNativeHost) + + override fun onCreate() { + // something between curly brace and super call + super.onCreate() + SoLoader.init(this, false) + if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { + // If you opted-in for the New Architecture, we load the native entry point for this app. + load() + } + ReactNativeFlipper.initializeFlipper(this, reactNativeHost.reactInstanceManager) + } +} diff --git a/packages/react-native-cli/src/lib/__test__/fixtures/MainApplication-before.kt b/packages/react-native-cli/src/lib/__test__/fixtures/MainApplication-before.kt new file mode 100644 index 0000000000..71fe2e5995 --- /dev/null +++ b/packages/react-native-cli/src/lib/__test__/fixtures/MainApplication-before.kt @@ -0,0 +1,45 @@ +package com.bugsnagreactnativeclitest + +import android.app.Application +import com.facebook.react.PackageList +import com.facebook.react.ReactApplication +import com.facebook.react.ReactHost +import com.facebook.react.ReactNativeHost +import com.facebook.react.ReactPackage +import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load +import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost +import com.facebook.react.defaults.DefaultReactNativeHost +import com.facebook.react.flipper.ReactNativeFlipper +import com.facebook.soloader.SoLoader + +class MainApplication : Application(), ReactApplication { + + override val reactNativeHost: ReactNativeHost = + object : DefaultReactNativeHost(this) { + override fun getPackages(): List = + PackageList(this).packages.apply { + // Packages that cannot be autolinked yet can be added manually here, for example: + // add(MyReactNativePackage()) + } + + override fun getJSMainModuleName(): String = "index" + + override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG + + override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED + override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED + } + + override val reactHost: ReactHost + get() = getDefaultReactHost(this.applicationContext, reactNativeHost) + + override fun onCreate() { + super.onCreate() + SoLoader.init(this, false) + if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { + // If you opted-in for the New Architecture, we load the native entry point for this app. + load() + } + ReactNativeFlipper.initializeFlipper(this, reactNativeHost.reactInstanceManager) + } +} diff --git a/packages/react-native-cli/src/lib/__test__/fixtures/root-build-before-without-agp-version.gradle b/packages/react-native-cli/src/lib/__test__/fixtures/root-build-before-without-agp-version.gradle new file mode 100644 index 0000000000..842db470dc --- /dev/null +++ b/packages/react-native-cli/src/lib/__test__/fixtures/root-build-before-without-agp-version.gradle @@ -0,0 +1,37 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + ext { + buildToolsVersion = "29.0.2" + minSdkVersion = 16 + compileSdkVersion = 29 + targetSdkVersion = 29 + } + repositories { + google() + jcenter() + } + dependencies { + classpath("com.android.tools.build:gradle") + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + 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") + } + + google() + jcenter() + maven { url 'https://www.jitpack.io' } + } +}