diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index 2be19aa7..ed84922f 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -1,17 +1,8 @@ apply plugin: "com.android.application" +apply plugin: "org.jetbrains.kotlin.android" apply plugin: "com.facebook.react" -import com.android.build.OutputFile - def projectRoot = rootDir.getAbsoluteFile().getParentFile().getAbsolutePath() -def expoDebuggableVariants = ['debug'] -// Override `debuggableVariants` for expo-updates debugging -if (System.getenv('EX_UPDATES_NATIVE_DEBUG') == "1") { - react { - expoDebuggableVariants = [] - } -} - /** * This is the configuration block to customize your React Native Android app. @@ -21,17 +12,20 @@ react { entryFile = file(["node", "-e", "require('expo/scripts/resolveAppEntry')", projectRoot, "android", "absolute"].execute(null, rootDir).text.trim()) reactNativeDir = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsoluteFile() hermesCommand = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsolutePath() + "/sdks/hermesc/%OS-BIN%/hermesc" - debuggableVariants = expoDebuggableVariants + codegenDir = new File(["node", "--print", "require.resolve('@react-native/codegen/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim()).getParentFile().getAbsoluteFile() + + // Use Expo CLI to bundle the app, this ensures the Metro config + // works correctly with Expo projects. + cliFile = new File(["node", "--print", "require.resolve('@expo/cli', { paths: [require.resolve('expo/package.json')] })"].execute(null, rootDir).text.trim()) + bundleCommand = "export:embed" /* Folders */ // The root of your project, i.e. where "package.json" lives. Default is '..' // root = file("../") // The folder where the react-native NPM package is. Default is ../node_modules/react-native // reactNativeDir = file("../node_modules/react-native") - // The folder where the react-native Codegen package is. Default is ../node_modules/react-native-codegen - // codegenDir = file("../node_modules/react-native-codegen") - // The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js - // cliFile = file("../node_modules/react-native/cli.js") + // The folder where the react-native Codegen package is. Default is ../node_modules/@react-native/codegen + // codegenDir = file("../node_modules/@react-native/codegen") /* Variants */ // The list of variants to that are debuggable. For those we're going to @@ -42,9 +36,7 @@ react { /* Bundling */ // A list containing the node command and its flags. Default is just 'node'. // nodeExecutableAndArgs = ["node"] - // - // The command to run when bundling. By default is 'bundle' - // bundleCommand = "ram-bundle" + // // The path to the CLI configuration file. Default is empty. // bundleConfig = file(../rn-cli.config.js) @@ -67,19 +59,6 @@ react { // hermesFlags = ["-O", "-output-source-map"] } -// Override `hermesEnabled` by `expo.jsEngine` -ext { - hermesEnabled = (findProperty('expo.jsEngine') ?: "hermes") == "hermes" -} - -/** - * Set this to true to create four separate APKs instead of one, - * one for each native architecture. This is useful if you don't - * use App Bundles (https://developer.android.com/guide/app-bundle/) - * and want to have separate APKs to upload to the Play Store. - */ -def enableSeparateBuildPerCPUArchitecture = false - /** * Set this to true to Run Proguard on Release builds to minify the Java bytecode. */ @@ -98,37 +77,21 @@ def enableProguardInReleaseBuilds = (findProperty('android.enableProguardInRelea */ def jscFlavor = 'org.webkit:android-jsc:+' -/** - * Private function to get the list of Native Architectures you want to build. - * This reads the value from reactNativeArchitectures in your gradle.properties - * file and works together with the --active-arch-only flag of react-native run-android. - */ -def reactNativeArchitectures() { - def value = project.getProperties().get("reactNativeArchitectures") - return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"] -} - android { ndkVersion rootProject.ext.ndkVersion - compileSdkVersion rootProject.ext.compileSdkVersion + buildToolsVersion rootProject.ext.buildToolsVersion + compileSdk rootProject.ext.compileSdkVersion - namespace "com.rnctvexample" + namespace 'com.rnctvexample' defaultConfig { applicationId 'com.rnctvexample' minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion versionCode 1 versionName "1.0.0" - } - splits { - abi { - reset() - enable enableSeparateBuildPerCPUArchitecture - universalApk false // If true, also generate a universal APK - include (*reactNativeArchitectures()) - } + buildConfigField("boolean", "REACT_NATIVE_UNSTABLE_USE_RUNTIME_SCHEDULER_ALWAYS", (findProperty("reactNative.unstable_useRuntimeSchedulerAlways") ?: true).toString()) } signingConfigs { debug { @@ -151,20 +114,9 @@ android { proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" } } - - // applicationVariants are e.g. debug, release - applicationVariants.all { variant -> - variant.outputs.each { output -> - // For each separate APK per architecture, set a unique version code as described here: - // https://developer.android.com/studio/build/configure-apk-splits.html - // Example: versionCode 1 will generate 1001 for armeabi-v7a, 1002 for x86, etc. - def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4] - def abi = output.getFilter(OutputFile.ABI) - if (abi != null) { // null for the universal-debug, universal-release variants - output.versionCodeOverride = - defaultConfig.versionCode * 1000 + versionCodes.get(abi) - } - + packagingOptions { + jniLibs { + useLegacyPackaging (findProperty('expo.useLegacyPackaging')?.toBoolean() ?: false) } } } @@ -196,35 +148,22 @@ dependencies { def isGifEnabled = (findProperty('expo.gif.enabled') ?: "") == "true"; def isWebpEnabled = (findProperty('expo.webp.enabled') ?: "") == "true"; def isWebpAnimatedEnabled = (findProperty('expo.webp.animated') ?: "") == "true"; - def frescoVersion = rootProject.ext.frescoVersion - - // If your app supports Android versions before Ice Cream Sandwich (API level 14) - if (isGifEnabled || isWebpEnabled) { - implementation("com.facebook.fresco:fresco:${frescoVersion}") - implementation("com.facebook.fresco:imagepipeline-okhttp3:${frescoVersion}") - } if (isGifEnabled) { // For animated gif support - implementation("com.facebook.fresco:animated-gif:${frescoVersion}") + implementation("com.facebook.fresco:animated-gif:${reactAndroidLibs.versions.fresco.get()}") } if (isWebpEnabled) { // For webp support - implementation("com.facebook.fresco:webpsupport:${frescoVersion}") + implementation("com.facebook.fresco:webpsupport:${reactAndroidLibs.versions.fresco.get()}") if (isWebpAnimatedEnabled) { // Animated webp support - implementation("com.facebook.fresco:animated-webp:${frescoVersion}") + implementation("com.facebook.fresco:animated-webp:${reactAndroidLibs.versions.fresco.get()}") } } - implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.0.0") - - debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") - debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") { - exclude group:'com.squareup.okhttp3', module:'okhttp' - } - debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") + implementation("com.facebook.react:flipper-integration") if (hermesEnabled.toBoolean()) { implementation("com.facebook.react:hermes-android") @@ -233,5 +172,5 @@ dependencies { } } -apply from: new File(["node", "--print", "require.resolve('@react-native-community/cli-platform-android/package.json')"].execute(null, rootDir).text.trim(), "../native_modules.gradle"); +apply from: new File(["node", "--print", "require.resolve('@react-native-community/cli-platform-android/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim(), "../native_modules.gradle"); applyNativeModulesAppBuildGradle(project) diff --git a/example/android/app/src/debug/AndroidManifest.xml b/example/android/app/src/debug/AndroidManifest.xml index 99e38fc5..3ec2507b 100644 --- a/example/android/app/src/debug/AndroidManifest.xml +++ b/example/android/app/src/debug/AndroidManifest.xml @@ -3,5 +3,5 @@ - + diff --git a/example/android/app/src/debug/java/com/rnctvexample/ReactNativeFlipper.java b/example/android/app/src/debug/java/com/rnctvexample/ReactNativeFlipper.java deleted file mode 100644 index 9e033a3b..00000000 --- a/example/android/app/src/debug/java/com/rnctvexample/ReactNativeFlipper.java +++ /dev/null @@ -1,75 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - *

This source code is licensed under the MIT license found in the LICENSE file in the root - * directory of this source tree. - */ -package com.rnctvexample; - -import android.content.Context; -import com.facebook.flipper.android.AndroidFlipperClient; -import com.facebook.flipper.android.utils.FlipperUtils; -import com.facebook.flipper.core.FlipperClient; -import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin; -import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin; -import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin; -import com.facebook.flipper.plugins.inspector.DescriptorMapping; -import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin; -import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor; -import com.facebook.flipper.plugins.network.NetworkFlipperPlugin; -import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin; -import com.facebook.react.ReactInstanceEventListener; -import com.facebook.react.ReactInstanceManager; -import com.facebook.react.bridge.ReactContext; -import com.facebook.react.modules.network.NetworkingModule; -import okhttp3.OkHttpClient; - -/** - * Class responsible of loading Flipper inside your React Native application. This is the debug - * flavor of it. Here you can add your own plugins and customize the Flipper setup. - */ -public class ReactNativeFlipper { - public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { - if (FlipperUtils.shouldEnableFlipper(context)) { - final FlipperClient client = AndroidFlipperClient.getInstance(context); - - client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults())); - client.addPlugin(new DatabasesFlipperPlugin(context)); - client.addPlugin(new SharedPreferencesFlipperPlugin(context)); - client.addPlugin(CrashReporterPlugin.getInstance()); - - NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin(); - NetworkingModule.setCustomClientBuilder( - new NetworkingModule.CustomClientBuilder() { - @Override - public void apply(OkHttpClient.Builder builder) { - builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin)); - } - }); - client.addPlugin(networkFlipperPlugin); - client.start(); - - // Fresco Plugin needs to ensure that ImagePipelineFactory is initialized - // Hence we run if after all native modules have been initialized - ReactContext reactContext = reactInstanceManager.getCurrentReactContext(); - if (reactContext == null) { - reactInstanceManager.addReactInstanceEventListener( - new ReactInstanceEventListener() { - @Override - public void onReactContextInitialized(ReactContext reactContext) { - reactInstanceManager.removeReactInstanceEventListener(this); - reactContext.runOnNativeModulesQueueThread( - new Runnable() { - @Override - public void run() { - client.addPlugin(new FrescoFlipperPlugin()); - } - }); - } - }); - } else { - client.addPlugin(new FrescoFlipperPlugin()); - } - } - } -} diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index 1cf7c749..707e8b54 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -1,4 +1,4 @@ - + @@ -11,13 +11,12 @@ - - - + + + - - + diff --git a/example/android/app/src/main/java/com/rnctvexample/MainActivity.java b/example/android/app/src/main/java/com/rnctvexample/MainActivity.java deleted file mode 100644 index 127430de..00000000 --- a/example/android/app/src/main/java/com/rnctvexample/MainActivity.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.rnctvexample; - -import android.os.Build; -import android.os.Bundle; - -import com.facebook.react.ReactActivity; -import com.facebook.react.ReactActivityDelegate; -import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint; -import com.facebook.react.defaults.DefaultReactActivityDelegate; - -import expo.modules.ReactActivityDelegateWrapper; - -public class MainActivity extends ReactActivity { - @Override - protected void onCreate(Bundle savedInstanceState) { - // Set the theme to AppTheme BEFORE onCreate to support - // coloring the background, status bar, and navigation bar. - // This is required for expo-splash-screen. - setTheme(R.style.AppTheme); - super.onCreate(null); - } - - /** - * Returns the name of the main component registered from JavaScript. - * This is used to schedule rendering of the component. - */ - @Override - protected String getMainComponentName() { - return "main"; - } - - /** - * Returns the instance of the {@link ReactActivityDelegate}. Here we use a util class {@link - * DefaultReactActivityDelegate} which allows you to easily enable Fabric and Concurrent React - * (aka React 18) with two boolean flags. - */ - @Override - protected ReactActivityDelegate createReactActivityDelegate() { - return new ReactActivityDelegateWrapper(this, BuildConfig.IS_NEW_ARCHITECTURE_ENABLED, new DefaultReactActivityDelegate( - this, - getMainComponentName(), - // If you opted-in for the New Architecture, we enable the Fabric Renderer. - DefaultNewArchitectureEntryPoint.getFabricEnabled(), // fabricEnabled - // If you opted-in for the New Architecture, we enable Concurrent React (i.e. React 18). - DefaultNewArchitectureEntryPoint.getConcurrentReactEnabled() // concurrentRootEnabled - )); - } - - /** - * Align the back button behavior with Android S - * where moving root activities to background instead of finishing activities. - * @see onBackPressed - */ - @Override - public void invokeDefaultOnBackPressed() { - if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) { - if (!moveTaskToBack(false)) { - // For non-root activities, use the default implementation to finish them. - super.invokeDefaultOnBackPressed(); - } - return; - } - - // Use the default back button implementation on Android S - // because it's doing more than {@link Activity#moveTaskToBack} in fact. - super.invokeDefaultOnBackPressed(); - } -} diff --git a/example/android/app/src/main/java/com/rnctvexample/MainActivity.kt b/example/android/app/src/main/java/com/rnctvexample/MainActivity.kt new file mode 100644 index 00000000..d206e317 --- /dev/null +++ b/example/android/app/src/main/java/com/rnctvexample/MainActivity.kt @@ -0,0 +1,61 @@ +package com.rnctvexample + +import android.os.Build +import android.os.Bundle + +import com.facebook.react.ReactActivity +import com.facebook.react.ReactActivityDelegate +import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled +import com.facebook.react.defaults.DefaultReactActivityDelegate + +import expo.modules.ReactActivityDelegateWrapper + +class MainActivity : ReactActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + // Set the theme to AppTheme BEFORE onCreate to support + // coloring the background, status bar, and navigation bar. + // This is required for expo-splash-screen. + setTheme(R.style.AppTheme); + super.onCreate(null) + } + + /** + * Returns the name of the main component registered from JavaScript. This is used to schedule + * rendering of the component. + */ + override fun getMainComponentName(): String = "main" + + /** + * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate] + * which allows you to enable New Architecture with a single boolean flags [fabricEnabled] + */ + override fun createReactActivityDelegate(): ReactActivityDelegate { + return ReactActivityDelegateWrapper( + this, + BuildConfig.IS_NEW_ARCHITECTURE_ENABLED, + object : DefaultReactActivityDelegate( + this, + mainComponentName, + fabricEnabled + ){}) + } + + /** + * Align the back button behavior with Android S + * where moving root activities to background instead of finishing activities. + * @see onBackPressed + */ + override fun invokeDefaultOnBackPressed() { + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) { + if (!moveTaskToBack(false)) { + // For non-root activities, use the default implementation to finish them. + super.invokeDefaultOnBackPressed() + } + return + } + + // Use the default back button implementation on Android S + // because it's doing more than [Activity.moveTaskToBack] in fact. + super.invokeDefaultOnBackPressed() + } +} diff --git a/example/android/app/src/main/java/com/rnctvexample/MainApplication.java b/example/android/app/src/main/java/com/rnctvexample/MainApplication.java deleted file mode 100644 index 5731ffa1..00000000 --- a/example/android/app/src/main/java/com/rnctvexample/MainApplication.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.rnctvexample; - -import android.app.Application; -import android.content.res.Configuration; -import androidx.annotation.NonNull; - -import com.facebook.react.PackageList; -import com.facebook.react.ReactApplication; -import com.facebook.react.ReactNativeHost; -import com.facebook.react.ReactPackage; -import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint; -import com.facebook.react.defaults.DefaultReactNativeHost; -import com.facebook.soloader.SoLoader; - -import expo.modules.ApplicationLifecycleDispatcher; -import expo.modules.ReactNativeHostWrapper; - -import java.util.List; - -public class MainApplication extends Application implements ReactApplication { - - private final ReactNativeHost mReactNativeHost = - new ReactNativeHostWrapper(this, new DefaultReactNativeHost(this) { - @Override - public boolean getUseDeveloperSupport() { - return BuildConfig.DEBUG; - } - - @Override - protected List getPackages() { - @SuppressWarnings("UnnecessaryLocalVariable") - List packages = new PackageList(this).getPackages(); - // Packages that cannot be autolinked yet can be added manually here, for example: - // packages.add(new MyReactNativePackage()); - return packages; - } - - @Override - protected String getJSMainModuleName() { - return "index"; - } - - @Override - protected boolean isNewArchEnabled() { - return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; - } - - @Override - protected Boolean isHermesEnabled() { - return BuildConfig.IS_HERMES_ENABLED; - } - }); - - @Override - public ReactNativeHost getReactNativeHost() { - return mReactNativeHost; - } - - @Override - public void onCreate() { - super.onCreate(); - SoLoader.init(this, /* native exopackage */ false); - if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { - // If you opted-in for the New Architecture, we load the native entry point for this app. - DefaultNewArchitectureEntryPoint.load(); - } - ReactNativeFlipper.initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); - ApplicationLifecycleDispatcher.onApplicationCreate(this); - } - - @Override - public void onConfigurationChanged(@NonNull Configuration newConfig) { - super.onConfigurationChanged(newConfig); - ApplicationLifecycleDispatcher.onConfigurationChanged(this, newConfig); - } -} diff --git a/example/android/app/src/main/java/com/rnctvexample/MainApplication.kt b/example/android/app/src/main/java/com/rnctvexample/MainApplication.kt new file mode 100644 index 00000000..28e18ecf --- /dev/null +++ b/example/android/app/src/main/java/com/rnctvexample/MainApplication.kt @@ -0,0 +1,65 @@ +package com.rnctvexample + +import android.app.Application +import android.content.res.Configuration +import androidx.annotation.NonNull + +import com.facebook.react.PackageList +import com.facebook.react.ReactApplication +import com.facebook.react.ReactNativeHost +import com.facebook.react.ReactPackage +import com.facebook.react.ReactHost +import com.facebook.react.config.ReactFeatureFlags +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 + +import expo.modules.ApplicationLifecycleDispatcher +import expo.modules.ReactNativeHostWrapper + +class MainApplication : Application(), ReactApplication { + + override val reactNativeHost: ReactNativeHost = ReactNativeHostWrapper( + this, + object : DefaultReactNativeHost(this) { + override fun getPackages(): List { + // Packages that cannot be autolinked yet can be added manually here, for example: + // packages.add(new MyReactNativePackage()); + return PackageList(this).packages + } + + override fun getJSMainModuleName(): String = ".expo/.virtual-metro-entry" + + 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.REACT_NATIVE_UNSTABLE_USE_RUNTIME_SCHEDULER_ALWAYS) { + ReactFeatureFlags.unstable_useRuntimeSchedulerAlways = 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() + } + if (BuildConfig.DEBUG) { + ReactNativeFlipper.initializeFlipper(this, reactNativeHost.reactInstanceManager) + } + ApplicationLifecycleDispatcher.onApplicationCreate(this) + } + + override fun onConfigurationChanged(newConfig: Configuration) { + super.onConfigurationChanged(newConfig) + ApplicationLifecycleDispatcher.onConfigurationChanged(this, newConfig) + } +} diff --git a/example/android/app/src/main/res/drawable/rn_edit_text_material.xml b/example/android/app/src/main/res/drawable/rn_edit_text_material.xml index f35d9962..73b37e4d 100644 --- a/example/android/app/src/main/res/drawable/rn_edit_text_material.xml +++ b/example/android/app/src/main/res/drawable/rn_edit_text_material.xml @@ -20,7 +20,7 @@ android:insetBottom="@dimen/abc_edit_text_inset_bottom_material"> -