介绍使用 Cordova 12 的应用程序,该应用程序需要目标 SDK Android 13 / API 33。我的应用程序依赖于以下插件(以及许多其他插件)...
cordova-plugin-camera
cordova-plugin-media-capture
两个插件都会在 AndroidManifest.xml 中插入权限。升级到 Cordova 12 并将 targetSdk 设置为 33 后,构建尝试合并权限失败...
> Task :app:processReleaseMainManifest FAILED
/Users/jmelvin/dev/sizzlescene/repos/mobile/platforms/android/app/src/main/AndroidManifest.xml:47:5-108 Error:
Element uses-permission#android.permission.WRITE_EXTERNAL_STORAGE at AndroidManifest.xml:47:5-108 duplicated with element declared at AndroidManifest.xml:26:5-81
以下是 cordova-plugin-camera 插件插入的属性...
11a12,14
> <provider android:authorities="${applicationId}.cordova.plugin.camera.provider" android:exported="false" android:grantUriPermissions="true" android:name="org.apache.cordova.camera.FileProvider">
> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/camera_provider_paths" />
> </provider>
22a26,41
> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
> <queries>
> <intent>
> <action android:name="android.media.action.IMAGE_CAPTURE" />
> </intent>
> <intent>
> <action android:name="android.intent.action.GET_CONTENT" />
> </intent>
> <intent>
> <action android:name="android.intent.action.PICK" />
> </intent>
> <intent>
> <action android:name="com.android.camera.action.CROP" />
> <data android:mimeType="image/*" android:scheme="content" />
> </intent>
> </queries>
以下是 cordova-plugin-media-capture 插件添加的属性...
22a23,28
> <uses-permission android:name="android.permission.RECORD_AUDIO" />
> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
> <uses-permission android:maxSdkVersion="32" android:name="android.permission.READ_EXTERNAL_STORAGE" />
> <uses-permission android:maxSdkVersion="32" android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
最后,当两个插件都包含在构建中时......
11a12,14
> <provider android:authorities="${applicationId}.cordova.plugin.camera.provider" android:exported="false" android:grantUriPermissions="true" android:name="org.apache.cordova.camera.FileProvider">
> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/camera_provider_paths" />
> </provider>
22a26,47
> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
> <queries>
> <intent>
> <action android:name="android.media.action.IMAGE_CAPTURE" />
> </intent>
> <intent>
> <action android:name="android.intent.action.GET_CONTENT" />
> </intent>
> <intent>
> <action android:name="android.intent.action.PICK" />
> </intent>
> <intent>
> <action android:name="com.android.camera.action.CROP" />
> <data android:mimeType="image/*" android:scheme="content" />
> </intent>
> </queries>
> <uses-permission android:name="android.permission.RECORD_AUDIO" />
> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
> <uses-permission android:maxSdkVersion="32" android:name="android.permission.READ_EXTERNAL_STORAGE" />
> <uses-permission android:maxSdkVersion="32" android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
WRITE_EXTERNAL_STORAGE 的权限请求并不完全相同。媒体捕获附带 SDK 限定符...
camera: android:name="android.permission.WRITE_EXTERNAL_STORAGE"
capture: android:maxSdkVersion="32" android:name="android.permission.WRITE_EXTERNAL_STORAGE"
手动删除捕获插件条目确实可以让构建成功完成。但是,我不确定结果在功能上是否正确。
问题:这是清单合并代码中的错误,还是有解决方法来避免冲突并保持功能相同?
问题:这是清单合并代码中的错误,还是有解决方法来避免冲突并保持功能相同?
这不是一个错误,通常在编写原生项目时,如果两个库尝试使用不同的配置声明相同的权限,则会导致类似的错误。
什么是 bug,事实上 Cordova 的 <edit-config>
/
<config-file>
指令会导致最终结果中的冲突和/或重复指令,这已经是一个 bug 好几年了。但是可以使用钩子来纠正项目
after_prepare
stripExtraWriteExternalStoragePerm.js
目录中添加
hooks/
文件:
const FS = require('fs');
const Path = require('path');
let path = Path.resolve('platforms/android/app/src/main/AndroidManifest.xml');
let manifest = FS.readFileSync(path, {
encoding: 'utf-8'
});
// Strips ALL occurrences of <uses-permission android:name="androoid.permission.WRITE_EXTERNAL_STORAGE" />
// If you have several conflicts (of different maxSDKVersion, or in different formats) then the regex
// may need to be adjusted, or repeated for each format.
manifest = manifest.replace(/^(\s)+<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" \/>$/gm, '');
FS.writeFileSync(path, manifest);
在您的config.xml
中添加:
<widget ...>
...
<platform name="android">
...
<hook type="after_prepare" src="hooks/stripExtraWritePerm.js" />
</platform>
</widget>
如果您已经有一个适用于 Android 的 <platform>
块,那么您应该将其添加到现有的
<platform>
块中。正如 JS 注释所述,任何插件组合都可能会发生冲突,具体取决于它们如何声明
WRITE_EXTERNAL_STORAGE
(例如,有或没有
maxSDKVersion
属性,或者指定了不同的
maxSDKVersion
属性)。如果是这种情况,您可能需要为您的项目添加额外的
manifest = manifest.replace(...)
行。我最初为工作编写了钩子脚本,因此该代码是在 Apache 许可证下获得 Total Pave Inc. 的版权发布的:
https://gist.github.com/breautek/bd157b8598f9a816f2ec0d45e3d932c8