React Native集成Detox遇Manifest合并错误求助
React Native集成Detox时Android 12+的Manifest导出错误问题
问题重现
执行Detox构建命令:
detox build --configuration android.emu.debug
触发以下构建错误:
Task :app:processDebugMainManifest FAILED /home/erfan/Work/app-template/android/app/src/debug/AndroidManifest.xml:27:9-33:20 Error: android:exported needs to be explicitly specified for element <activity#androidx.test.core.app.InstrumentationActivityInvoker$BootstrapActivity>. Apps targeting Android 12 and higher are required to specify an explicit value for `android:exported` when the corresponding component has an intent filter defined. /home/erfan/Work/app-template/android/app/src/debug/AndroidManifest.xml:34:9-40:20 Error: android:exported needs to be explicitly specified for element <activity#androidx.test.core.app.InstrumentationActivityInvoker$EmptyActivity>. Apps targeting Android 12 and higher are required to specify an explicit value for `android:exported` when the corresponding component has an intent filter defined. /home/erfan/Work/app-template/android/app/src/debug/AndroidManifest.xml:41:9-47:20 Error: android:exported needs to be explicitly specified for element <activity#androidx.test.core.app.InstrumentationActivityInvoker$EmptyFloatingActivity>. Apps targeting Android 12 and higher are required to specify an explicit value for `android:exported` when the corresponding component has an intent filter defined.
错误指向的debug/AndroidManifest.xml文件不存在,已尝试以下方案未解决:
- 迁移到AndroidX
- 检查合并后的Manifest文件,未发现错误
- 添加
tools:replace属性
项目配置文件
主Manifest文件(android/app/src/main/AndroidManifest.xml)
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/> <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/> <application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:theme="@style/AppTheme" android:allowBackup="false" android:networkSecurityConfig="@xml/network_security_config"> <activity android:name=".MainActivity" android:label="@string/app_name" android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustPan" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
根级Gradle文件(android/build.gradle)
// Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { ext { kotlinVersion = "1.6.0" buildToolsVersion = "33.0.0" minSdkVersion = 21 compileSdkVersion = 33 targetSdkVersion = 33 androidXCore = "1.7.0" ndkVersion = "23.1.7779620" } repositories { google() mavenCentral() } dependencies { classpath("com.android.tools.build:gradle:7.3.1") classpath("com.facebook.react:react-native-gradle-plugin") classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") } } allprojects { repositories { maven { url("$rootDir/../node_modules/detox/Detox-android") } mavenCentral() google() maven { url 'https://www.jitpack.io' } } }
App级Gradle文件(android/app/build.gradle)
apply plugin: "com.android.application" apply plugin: "com.facebook.react" import com.android.build.OutputFile import org.apache.tools.ant.taskdefs.condition.Os react { // 配置内容已省略 } def enableSeparateBuildPerCPUArchitecture = false def enableProguardInReleaseBuilds = false def jscFlavor = 'org.webkit:android-jsc:+' def reactNativeArchitectures() { def value = project.getProperties().get("reactNativeArchitectures") return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"] } android { packagingOptions { pickFirst 'lib/x86/libc++_shared.so' pickFirst 'lib/x86_64/libjsc.so' pickFirst 'lib/arm64-v8a/libjsc.so' pickFirst 'lib/arm64-v8a/libc++_shared.so' pickFirst 'lib/x86_64/libc++_shared.so' pickFirst 'lib/armeabi-v7a/libc++_shared.so' } ndkVersion rootProject.ext.ndkVersion compileSdkVersion rootProject.ext.compileSdkVersion namespace "xxx" defaultConfig { applicationId "xxx" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion versionCode 75 versionName "2.17.2" testBuildType System.getProperty('testBuildType', 'debug') testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' } splits { abi { reset() enable enableSeparateBuildPerCPUArchitecture universalApk false include (*reactNativeArchitectures()) } } signingConfigs { debug { storeFile file('debug.keystore') storePassword 'android' keyAlias 'androiddebugkey' keyPassword 'android' } release { storeFile file('debug.keystore') storePassword 'android' keyAlias 'androiddebugkey' keyPassword 'android' } } buildTypes { debug { signingConfig signingConfigs.debug } release { signingConfig signingConfigs.release minifyEnabled enableProguardInReleaseBuilds proguardFile "${rootProject.projectDir}/../node_modules/detox/android/detox/proguard-rules-app.pro" proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" } } applicationVariants.all { variant -> variant.outputs.each { output -> def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4] def abi = output.getFilter(OutputFile.ABI) if (abi != null) { output.versionCodeOverride = defaultConfig.versionCode * 1000 + versionCodes.get(abi) } } } } dependencies { implementation project(':react-native-fs') implementation("com.facebook.react:react-android") 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}") if (hermesEnabled.toBoolean()) { implementation("com.facebook.react:hermes-android") } else { implementation jscFlavor } debugImplementation('com.wix:detox:+') implementation 'androidx.appcompat:appcompat:1.1.0' } apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) project.ext.vectoricons = [ iconFontNames: [ 'FontAwesome.ttf' ] ] apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"
解决方案
方法1:显式声明测试库Activity并设置android:exported
创建或修改android/app/src/debug/AndroidManifest.xml,添加以下内容:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <application> <!-- 适配Android 12+导出要求 --> <activity android:name="androidx.test.core.app.InstrumentationActivityInvoker$BootstrapActivity" android:exported="false" tools:node="merge" /> <activity android:name="androidx.test.core.app.InstrumentationActivityInvoker$EmptyActivity" android:exported="false" tools:node="merge" /> <activity android:name="androidx.test.core.app.InstrumentationActivityInvoker$EmptyFloatingActivity" android:exported="false" tools:node="merge" /> </application> </manifest>
tools:node="merge"用于合并依赖库中的Manifest配置,确保属性覆盖生效。
方法2:升级AndroidX测试核心库版本
在App级Gradle文件中显式指定AndroidX测试核心库的最新版本(1.5.0及以上已适配Android 12+):
debugImplementation 'androidx.test:core:1.5.0' androidTestImplementation 'androidx.test:core:1.5.0'
方法3:固定Detox版本
避免使用com.wix:detox:+的动态版本,改用适配Android 12+的稳定版,例如:
debugImplementation 'com.wix:detox:19.12.0'
内容的提问来源于stack exchange,提问作者Erfan Taghvaei
相关产品推荐
相关产品推荐

