diff --git a/ReactNativeNavigation.podspec b/ReactNativeNavigation.podspec index cbd33bf876a..59fbd0b47b8 100644 --- a/ReactNativeNavigation.podspec +++ b/ReactNativeNavigation.podspec @@ -6,7 +6,7 @@ package = JSON.parse(File.read(File.join(__dir__, 'package.json'))) fabric_enabled = ENV['RCT_NEW_ARCH_ENABLED'] == '1' # Detect if this is a Swift project by looking for user AppDelegate.swift files -start_dir = File.expand_path('../', __dir__) +start_dir = File.expand_path('../../', __dir__) swift_delegate_path = nil Find.find(start_dir) do |path| if path =~ /AppDelegate\.swift$/ @@ -26,6 +26,7 @@ end Pod::Spec.new do |s| s.name = "ReactNativeNavigation" + s.prepare_command = 'node autolink/postlink/__helpers__/generate_version_header.js' s.version = package['version'] s.summary = package['description'] @@ -40,11 +41,12 @@ Pod::Spec.new do |s| s.subspec 'Core' do |ss| s.source = { :git => "https://github.com/wix/react-native-navigation.git", :tag => "#{s.version}" } s.source_files = 'ios/**/*.{h,m,mm,cpp}' - s.exclude_files = "ios/ReactNativeNavigationTests/**/*.*", "lib/ios/OCMock/**/*.*" + s.exclude_files = "ios/ReactNativeNavigationTests/**/*.*", "ios/OCMock/**/*.*" # Only expose headers for Swift projects if swift_project s.public_header_files = [ - 'ios/RNNAppDelegate.h' + 'ios/RNNAppDelegate.h', + 'ios/ReactNativeVersionExtracted.h' ] end end diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 00000000000..eeea815a325 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,21 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# Default value: -Xmx10248m -XX:MaxPermSize=256m +# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 +# org.gradle.jvmargs=-Xmx4g -XX:MaxPermSize=1g -XX:+HeapDumpOnOutOfMemoryError -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCApplicationStoppedTime + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# android.useAndroidX=true +# android.enableJetifier=true diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000000..13372aef5e2 Binary files /dev/null and b/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..fd44bb50b67 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Thu Jan 04 11:01:32 EET 2018 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip diff --git a/android/gradlew b/android/gradlew new file mode 100755 index 00000000000..9d82f789151 --- /dev/null +++ b/android/gradlew @@ -0,0 +1,160 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/android/gradlew.bat b/android/gradlew.bat new file mode 100644 index 00000000000..8a0b282aa68 --- /dev/null +++ b/android/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 00000000000..e7b4def49cb --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1 @@ +include ':app' diff --git a/android/src/main/java/com/reactnativenavigation/react/NavigationPackage.kt b/android/src/main/java/com/reactnativenavigation/react/NavigationPackage.kt new file mode 100644 index 00000000000..5391b87c121 --- /dev/null +++ b/android/src/main/java/com/reactnativenavigation/react/NavigationPackage.kt @@ -0,0 +1,43 @@ +package com.reactnativenavigation + +import com.facebook.react.BaseReactPackage +import com.facebook.react.ReactApplication +import com.facebook.react.bridge.NativeModule +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.module.model.ReactModuleInfo +import com.facebook.react.module.model.ReactModuleInfoProvider +import com.facebook.react.uimanager.ViewManager +import com.reactnativenavigation.options.LayoutFactory +import com.reactnativenavigation.react.NavigationTurboModule +import com.reactnativenavigation.react.modal.ModalViewManager + +class NavigationPackage() : BaseReactPackage() { + + override fun getModule(name: String, context: ReactApplicationContext): NativeModule? { + val reactApp = context.applicationContext as ReactApplication + return when (name) { + NavigationTurboModule.NAME -> { + NavigationTurboModule(context, LayoutFactory(reactApp.reactHost)) + } + else -> { + null + } + } + } + + override fun getReactModuleInfoProvider() = ReactModuleInfoProvider { + mapOf(NavigationTurboModule.NAME to ReactModuleInfo( + name = NavigationTurboModule.NAME, + className = NavigationTurboModule.NAME, + canOverrideExistingModule = false, + needsEagerInit = false, + isCxxModule = false, + isTurboModule = true + )) + } + + override fun createViewManagers(reactContext: ReactApplicationContext): List> { + return mutableListOf(ModalViewManager(reactContext)) + } +} + diff --git a/autolink/postlink/__helpers__/generate_version_header.js b/autolink/postlink/__helpers__/generate_version_header.js new file mode 100644 index 00000000000..11e02a30226 --- /dev/null +++ b/autolink/postlink/__helpers__/generate_version_header.js @@ -0,0 +1,87 @@ +#!/usr/bin/env node +const fs = require('fs'); +const path = require('path'); +const { getReactNativeVersion, findProjectPackageJson } = require('./reactNativeVersion'); + +function generateVersionHeader() { + const startDir = __dirname; + + console.log(`Searching for project package.json from: ${startDir}`); + + const packageJsonPath = findProjectPackageJson(); + + if (!packageJsonPath) { + console.log('Warning: Project package.json not found'); + return; + } + + console.log(`Using package.json: ${packageJsonPath}`); + + const versionInfo = getReactNativeVersion(); + + if (!versionInfo) { + console.log('Warning: react-native not found in package.json'); + return; + } + + console.log(`Found React Native version: ${versionInfo.raw}`); + + const { major, minor, patch } = versionInfo; + + // Generate header content + const headerContent = `// + // ReactNativeVersionExtracted.h + // React Native version: ${versionInfo.raw} + // Generated on: ${new Date().toISOString()} + // Source: ${packageJsonPath} + // + + #ifndef ReactNativeVersionExtracted_h + #define ReactNativeVersionExtracted_h + + static const int REACT_NATIVE_VERSION_MAJOR = ${major}; + static const int REACT_NATIVE_VERSION_MINOR = ${minor}; + static const int REACT_NATIVE_VERSION_PATCH = ${patch}; + + #define RN_VERSION_MAJOR ${major} + #define RN_VERSION_MINOR ${minor} + #define RN_VERSION_PATCH ${patch} + + #endif + `; + + // Find RNN root by looking upwards from script location for RNN's package.json + let currentDir = __dirname; + let rnnPackageJson = null; + + for (let i = 0; i < 5; i++) { + const potential = path.join(currentDir, 'package.json'); + if (fs.existsSync(potential)) { + const pkg = JSON.parse(fs.readFileSync(potential, 'utf8')); + // This is RNN's package.json if name matches + if (pkg.name === 'react-native-navigation') { + rnnPackageJson = currentDir; + break; + } + } + currentDir = path.resolve(currentDir, '..'); + } + + if (!rnnPackageJson) { + console.log('Warning: Could not find react-native-navigation root'); + return; + } + + const outputFile = path.join(rnnPackageJson, 'ios/ReactNativeVersionExtracted.h'); + + fs.writeFileSync(outputFile, headerContent, 'utf8'); + console.log(`✅ Generated ${outputFile}`); + console.log(` Version: ${major}.${minor}.${patch}`); +} + +// Run if called directly +if (require.main === module) { + generateVersionHeader(); +} + +module.exports = { generateVersionHeader }; \ No newline at end of file diff --git a/autolink/postlink/__helpers__/reactNativeVersion.js b/autolink/postlink/__helpers__/reactNativeVersion.js new file mode 100644 index 00000000000..19f1d81f85f --- /dev/null +++ b/autolink/postlink/__helpers__/reactNativeVersion.js @@ -0,0 +1,76 @@ +// @ts-check +var fs = require('fs'); +var nodePath = require('path'); +var { warnn } = require('../log'); + +/** + * Find the project root package.json + * @returns {string|null} Path to project's package.json or null if not found + */ +function findProjectPackageJson() { + var searchDirs = [process.cwd(), __dirname]; + + for (var j = 0; j < searchDirs.length; j++) { + var searchDir = searchDirs[j]; + for (var i = 0; i < 10; i++) { + var packagePath = nodePath.join(searchDir, 'package.json'); + if (fs.existsSync(packagePath)) { + try { + var pkg = JSON.parse(fs.readFileSync(packagePath, 'utf8')); + if ((pkg.dependencies && pkg.dependencies['react-native']) || + (pkg.devDependencies && pkg.devDependencies['react-native'])) { + return packagePath; + } + } catch (e) { } + } + var parent = nodePath.dirname(searchDir); + if (parent === searchDir) break; + searchDir = parent; + } + } + + return null; +} + +/** + * Get React Native version as parsed object + * @returns {Object|null} { major, minor, patch, raw } or null + */ +function getReactNativeVersion() { + var projectPackageJsonPath = findProjectPackageJson(); + if (!projectPackageJsonPath) { + warnn('Could not find package.json to detect React Native version'); + return null; + } + + try { + var packageJson = JSON.parse(fs.readFileSync(projectPackageJsonPath, 'utf8')); + var rnVersion = packageJson.dependencies && packageJson.dependencies['react-native'] || + packageJson.devDependencies && packageJson.devDependencies['react-native']; + + if (!rnVersion) { + warnn('React Native not found in package.json'); + return null; + } + + // Parse version (remove ^, ~, >=, etc.) + var cleanVersion = rnVersion.replace(/^[\^~>=<]+/, ''); + var parts = cleanVersion.split('.'); + + return { + major: parseInt(parts[0]) || 0, + minor: parseInt(parts[1]) || 0, + patch: parseInt(parts[2]) || 0, + raw: rnVersion + }; + } catch (e) { + warnn('Error detecting React Native version: ' + e.message); + return null; + } +} + +module.exports = { + findProjectPackageJson: findProjectPackageJson, + getReactNativeVersion: getReactNativeVersion +}; + diff --git a/autolink/postlink/appDelegateLinker.js b/autolink/postlink/appDelegateLinker.js index 35ff99e10cb..856d866c980 100644 --- a/autolink/postlink/appDelegateLinker.js +++ b/autolink/postlink/appDelegateLinker.js @@ -10,6 +10,9 @@ class AppDelegateLinker { this.appDelegateHeaderPath = path.appDelegateHeader; this.removeUnneededImportsSuccess = false; this.removeApplicationLaunchContentSuccess = false; + const rnVersion = this._getReactNativeVersion(); + infon('Found React Native version: ' + (rnVersion ? rnVersion.raw : 'unknown')); + this.isRN79orHigher = rnVersion && (rnVersion.major > 0 || rnVersion.minor >= 79); } link() { @@ -20,7 +23,7 @@ class AppDelegateLinker { return; } - logn('Linking AppDelegate...'); + logn('Linking AppDelegate: ' + this.appDelegatePath); // New flow for Swift if (nodePath.extname(this.appDelegatePath) === '.swift') { @@ -194,16 +197,87 @@ class AppDelegateLinker { // SWIFT implementation _extendRNNAppDelegateSwift(content) { - return content + let newContent = content; + + newContent = newContent .replace( /import React_RCTAppDelegate/, 'import ReactNativeNavigation' ) + + // add this ONLY for < RN079 + if (!this.isRN79orHigher) { + newContent = this._updateRNNAppDelegateSwift_77_78(newContent); + } else { + newContent = this._updateRNNAppDelegateSwift_79(newContent); + } + + return newContent; + } + + _updateRNNAppDelegateSwift_77_78(content) { + return content .replace( /class AppDelegate: RCTAppDelegate/, 'class AppDelegate: RNNAppDelegate' ) } + _updateRNNAppDelegateSwift_79(content) { + let newContent = content; + newContent = newContent + .replace( + 'class AppDelegate: UIResponder, UIApplicationDelegate', + 'class AppDelegate: RNNAppDelegate' + ) + + newContent = newContent + .replace(/^\s*var window: UIWindow\?\s*$/gm, '') + .replace(/^\s*var reactNativeDelegate: ReactNativeDelegate\?\s*$/gm, '') + .replace(/^\s*var reactNativeFactory: RCTReactNativeFactory\?\s*$/gm, '') + + newContent = newContent + .replace( + /func application/, + 'override func application' + ) + + newContent = newContent + .replace( + /let delegate = ReactNativeDelegate\(\)/, + 'self.reactNativeDelegate = ReactNativeDelegate\(\)' + ) + + newContent = newContent + .replace( + /let factory = RCTReactNativeFactory\(delegate: delegate\)/, + 'super.application\(application, didFinishLaunchingWithOptions: launchOptions\)' + ) + + newContent = newContent + .replace(/^\s*delegate.dependencyProvider = RCTAppDependencyProvider\(\)\s*$/gm, '') + newContent = newContent + .replace(/^\s*reactNativeDelegate = delegate\s*$/gm, '') + newContent = newContent + .replace(/^\s*reactNativeFactory = factory\s*$/gm, '') + newContent = newContent + .replace(/^\s*window = UIWindow\(frame: UIScreen.main.bounds\)\s*$/gm, '') + newContent = newContent + .replace( + /factory\.startReactNative\([\s\S]*?withModuleName:\s*".*?"[\s\S]*?\)/g, + '' + ) + + return newContent; + } + + /** + * Get React Native version from package.json + * @returns {Object} { major, minor, patch } or null + */ + _getReactNativeVersion() { + const { getReactNativeVersion } = require('./__helpers__/reactNativeVersion'); + return getReactNativeVersion(); + } } module.exports = AppDelegateLinker; diff --git a/autolink/postlink/path.js b/autolink/postlink/path.js index c3fb62d4eba..6d7e79ef54a 100644 --- a/autolink/postlink/path.js +++ b/autolink/postlink/path.js @@ -9,8 +9,6 @@ var mainApplicationKotlin = glob.sync('**/MainApplication.kt', ignoreFolders)[0] exports.mainApplicationKotlin = mainApplicationKotlin; exports.rootGradle = mainApplicationKotlin.replace(/android\/app\/.*\.kt/, 'android/build.gradle'); -var reactNativeVersion = require('../../../react-native/package.json').version; -infon('Found React Native version: ' + reactNativeVersion); infon('Locating the AppDelegate.mm file ...'); exports.appDelegate = glob.sync( '**/AppDelegate.mm', diff --git a/ios/RNNAppDelegate.h b/ios/RNNAppDelegate.h index 91ab6ff2b88..5be8c6a0f7e 100644 --- a/ios/RNNAppDelegate.h +++ b/ios/RNNAppDelegate.h @@ -1,13 +1,41 @@ #import #import +#import -#if __has_include() -#import -#elif __has_include() -// for importing the header from framework, the dash will be transformed to underscore -#import +#if RN_VERSION_MAJOR == 0 && RN_VERSION_MINOR < 79 + #if __has_include() + #import + #elif __has_include() + #import + #endif + + #import +#else + #if __has_include() + #import + #elif __has_include() + #import + #endif +#endif + +#if __has_include() + #import +#elif __has_include() + #import #endif -@interface RNNAppDelegate : RCTAppDelegate +#import + +#if RN_VERSION_MAJOR == 0 && RN_VERSION_MINOR < 79 + @interface RNNAppDelegate : RCTAppDelegate +#else + @interface RNNAppDelegate : UIResponder + @property(nonatomic, strong) UIWindow *window; + + @property(nonatomic, strong) RCTDefaultReactNativeFactoryDelegate *reactNativeDelegate; + + @property(nonatomic, strong) RCTReactNativeFactory *reactNativeFactory; + @property(nonatomic) BOOL bridgelessEnabled; +#endif @end diff --git a/ios/RNNAppDelegate.mm b/ios/RNNAppDelegate.mm index 3bd9f71f214..9888a97f2a6 100644 --- a/ios/RNNAppDelegate.mm +++ b/ios/RNNAppDelegate.mm @@ -1,10 +1,8 @@ - #import "RNNAppDelegate.h" #import #import #import - #import "RCTAppSetupUtils.h" #import #import @@ -14,18 +12,12 @@ #import #import +#if RN_VERSION_MAJOR == 0 && RN_VERSION_MINOR < 79 + #import +#endif - -#if __has_include() -#import -#import -#elif __has_include() -#import -#import -#else -// RN 0.77 support -#define RN077 -#import +#if __has_include() + #import #endif #import @@ -39,100 +31,113 @@ #import + static NSString *const kRNConcurrentRoot = @"concurrentRoot"; -@interface RNNAppDelegate () { -} -@end +#if RN_VERSION_MAJOR == 0 && RN_VERSION_MINOR < 79 + @interface RNNAppDelegate () { + } + @end +#else + @interface RNNAppDelegate () { + } + @end +#endif @implementation RNNAppDelegate - (BOOL)application:(UIApplication *)application - didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { +didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { -#ifdef RN077 +#if RN_VERSION_MAJOR == 0 && RN_VERSION_MINOR < 79 [self _setUpFeatureFlags]; self.rootViewFactory = [self createRCTRootViewFactory]; [RCTComponentViewFactory currentComponentViewFactory].thirdPartyFabricComponentsProvider = self; RCTAppSetupPrepareApp(application, self.newArchEnabled); RCTSetNewArchEnabled(TRUE); -#else - self.reactNativeFactory = [RCTReactNativeFactory new]; - self.reactNativeFactory = [self.reactNativeFactory initWithDelegate:self]; -#endif RCTEnableTurboModuleInterop(YES); RCTEnableTurboModuleInteropBridgeProxy(YES); - + self.rootViewFactory.reactHost = [self.rootViewFactory createReactHost:launchOptions]; - + [ReactNativeNavigation bootstrapWithHost:self.rootViewFactory.reactHost]; - +#else + self.reactNativeFactory = [[RCTReactNativeFactory alloc] initWithDelegate:self.reactNativeDelegate]; + self.reactNativeDelegate.dependencyProvider = [RCTAppDependencyProvider new]; + + RCTAppSetupPrepareApp(application, YES); + RCTEnableTurboModuleInteropBridgeProxy(YES); + + self.reactNativeFactory.rootViewFactory.reactHost = [self.reactNativeFactory.rootViewFactory createReactHost:launchOptions]; + + [ReactNativeNavigation bootstrapWithHost:self.reactNativeFactory.rootViewFactory.reactHost]; +#endif + return YES; } + +#if RN_VERSION_MAJOR == 0 && RN_VERSION_MINOR < 79 - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge { - [NSException raise:@"RCTBridgeDelegate::sourceURLForBridge not implemented" - format:@"Subclasses must implement a valid sourceURLForBridge method"]; - return nil; + [NSException raise:@"RCTBridgeDelegate::sourceURLForBridge not implemented" + format:@"Subclasses must implement a valid sourceURLForBridge method"]; + return nil; } - (BOOL)concurrentRootEnabled { - return true; + return true; } - - -#ifdef RN077 - (RCTRootViewFactory *)createRCTRootViewFactory { - __weak __typeof(self) weakSelf = self; - RCTBundleURLBlock bundleUrlBlock = ^{ - RCTAppDelegate *strongSelf = weakSelf; - return strongSelf.bundleURL; - }; - - RCTRootViewFactoryConfiguration *configuration = - [[RCTRootViewFactoryConfiguration alloc] initWithBundleURLBlock:bundleUrlBlock - newArchEnabled:self.newArchEnabled]; - - - return [[RCTRootViewFactory alloc] initWithConfiguration:configuration andTurboModuleManagerDelegate:self]; + __weak __typeof(self) weakSelf = self; + RCTBundleURLBlock bundleUrlBlock = ^{ + RCTAppDelegate *strongSelf = weakSelf; + return strongSelf.bundleURL; + }; + + RCTRootViewFactoryConfiguration *configuration = + [[RCTRootViewFactoryConfiguration alloc] initWithBundleURLBlock:bundleUrlBlock + newArchEnabled:self.newArchEnabled]; + + + return [[RCTRootViewFactory alloc] initWithConfiguration:configuration andTurboModuleManagerDelegate:self]; } - #pragma mark - Feature Flags class RCTAppDelegateBridgelessFeatureFlags : public facebook::react::ReactNativeFeatureFlagsDefaults { - public: - bool enableBridgelessArchitecture() override - { - return true; - } - bool enableFabricRenderer() override - { - return true; - } - bool useTurboModules() override - { - return true; - } - bool useNativeViewConfigsInBridgelessMode() override - { - return true; - } - bool enableFixForViewCommandRace() override - { - return true; - } +public: + bool enableBridgelessArchitecture() override + { + return true; + } + bool enableFabricRenderer() override + { + return true; + } + bool useTurboModules() override + { + return true; + } + bool useNativeViewConfigsInBridgelessMode() override + { + return true; + } + + + bool enableFixForViewCommandRace() override + { + return true; + } }; - (void)_setUpFeatureFlags { facebook::react::ReactNativeFeatureFlags::override( - std::make_unique()); + std::make_unique()); } #endif @end - diff --git a/metro.config.js b/metro.config.js index fe3f5db917c..67f1d24f188 100644 --- a/metro.config.js +++ b/metro.config.js @@ -1,11 +1,25 @@ +const path = require('path'); const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config'); +const root = path.resolve(__dirname); + const config = { - projectRoot: `${__dirname}`, + projectRoot: root, + watchFolders: [root], resolver: { - enableGlobalPackages: true, + nodeModulesPaths: [path.resolve(root, 'node_modules')], + extraNodeModules: new Proxy( + {}, + { + get: (target, name) => { + if (name === 'react-native-navigation') { + return root; + } + return path.join(root, 'node_modules', name); + }, + } + ), }, - watchFolders: [__dirname], }; module.exports = mergeConfig(getDefaultConfig(__dirname), config); diff --git a/playground/ios/playground.xcodeproj/xcshareddata/xcschemes/playground.xcscheme b/playground/ios/playground.xcodeproj/xcshareddata/xcschemes/playground.xcscheme index 85bb8358bcc..f6186cdf373 100644 --- a/playground/ios/playground.xcodeproj/xcshareddata/xcschemes/playground.xcscheme +++ b/playground/ios/playground.xcodeproj/xcshareddata/xcschemes/playground.xcscheme @@ -15,7 +15,7 @@ diff --git a/playground/ios/playground/AppDelegate.mm b/playground/ios/playground/AppDelegate.mm index 1b68e1e2a86..8664bd12076 100644 --- a/playground/ios/playground/AppDelegate.mm +++ b/playground/ios/playground/AppDelegate.mm @@ -1,54 +1,73 @@ #import "AppDelegate.h" #import "RNNCustomViewController.h" -#import -#import #import -@interface AppDelegate () -@end +#if RN_VERSION_MAJOR == 0 && RN_VERSION_MINOR < 79 + @interface AppDelegate () + @end +#else + @interface AppDelegate () + @end + + @interface ReactNativeDelegate : RCTDefaultReactNativeFactoryDelegate + @end + + @implementation ReactNativeDelegate + - (NSURL *)bundleURL + { + #if DEBUG + return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; + #else + return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; + #endif + } + - (BOOL)newArchEnabled + { + return YES; + } + + @end +#endif + + @implementation AppDelegate - (BOOL)application:(UIApplication *)application - didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { +didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + self.reactNativeDelegate = [ReactNativeDelegate new]; [super application:application didFinishLaunchingWithOptions:launchOptions]; - self.dependencyProvider = [RCTAppDependencyProvider new]; - - if (self.bridgelessEnabled) { -#ifdef RCT_NEW_ARCH_ENABLED - [ReactNativeNavigation - registerExternalHostComponent: @"RNNCustomComponent" - callback:^UIViewController *(NSDictionary *props, RCTHost *host) { - return [[RNNCustomViewController alloc] initWithProps:props]; - }]; +#if RN_VERSION_MAJOR == 0 && RN_VERSION_MINOR < 79 + self.dependencyProvider = [RCTAppDependencyProvider new]; #endif - } else { - [ReactNativeNavigation - registerExternalComponent:@"RNNCustomComponent" - callback:^UIViewController *(NSDictionary *props, RCTBridge *bridge) { - return [[RNNCustomViewController alloc] initWithProps:props]; - }]; - } + + [ReactNativeNavigation + registerExternalHostComponent: @"RNNCustomComponent" + callback:^UIViewController *(NSDictionary *props, RCTHost *host) { + return [[RNNCustomViewController alloc] initWithProps:props]; + }]; return YES; } -#pragma mark - RCTBridgeDelegate - -- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge -{ - return [self bundleURL]; -} +#if RN_VERSION_MAJOR == 0 && RN_VERSION_MINOR < 79 + #pragma mark - RCTBridgeDelegate + - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge + { + return [self bundleURL]; + } -- (NSURL *)bundleURL -{ -#if DEBUG - return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; -#else - return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; + - (NSURL *)bundleURL + { + #if DEBUG + return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; + #else + return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; + #endif + } #endif -} @end +