如何制作同时支持 32 位和 64 位架构的 Android 应用程序?

Posted

技术标签:

【中文标题】如何制作同时支持 32 位和 64 位架构的 Android 应用程序?【英文标题】:How to make Android apps which support both 32-bit and 64-bit architecture? 【发布时间】:2018-07-10 23:59:39 【问题描述】:

我刚刚收到并阅读了a newsletter from Google Play 提到,从明年开始,商店“将要求新应用程序和带有本机库的应用程序更新提供 32 位版本之外的 64 位版本”。

对于尚未阅读的人,它指出:

2019 年 64 位支持要求

android 中引入了对 64 位架构的平台支持 5.0。今天,超过 40% 的在线 Android 设备支持 64 位,同时仍保持 32 位兼容性。对于应用程序 使用本机库,64 位代码通常提供显着 更好的性能,额外的寄存器和新的指令。

期待未来支持 64 位代码的 Android 设备 仅,Play 管理中心将要求新应用和应用更新 除了 32 位之外,本机库还提供 64 位版本 版本。这可以在单个 APK 中,也可以作为多个 APK 之一 APK 已发布。

我们不会删除 32 位支持。 Google Play 将继续 支持 32 位应用程序和设备。不包含本机代码的应用 不受影响。

此更改将于 2019 年 8 月生效。我们提供 今天提前通知,以便为不这样做的开发人员留出足够的时间 还支持 64 位规划过渡。敬请期待未来 我们将在其中深入研究性能优势 Android 上的 64 位本机库,并查看 CPU 和 NDK 架构指南了解更多信息。

如果适用,我们需要进行哪些实际更改才能完全符合这一新要求?

【问题讨论】:

如果您有自己的 NDK 代码,则需要支持 64 位版本的 ABI。如果您没有自己的 NDK 代码,但您使用的库有,则他们需要提供支持 64 位 CPU 架构的库版本。 感谢您的回答,CommonsWare!从你的回答和我读到的东西来看,它似乎并没有那么复杂。让我再问你一件事:如果开发人员既不拥有也不使用 NDK 代码,这是否意味着常规应用程序已经为两者做好了准备?另外,如果您想提供文本作为答案,我很乐意接受。 "如果开发者既不拥有也不使用 NDK 代码,是否意味着常规应用已经为两者做好了准备?" - 由于我不确定您所说的“既不拥有也不使用”是什么意思,我无法回答,抱歉。换句话说:如果您检查您的 APK(例如,在 Android Studio 中分析 APK),并且您没有找到包含 .so 文件的 lib/ 目录,那么您无需对此进行任何操作即将到来的要求。如果您确实找到 .so 文件,但在名册中看不到 64 位架构,则需要找到这些 .so 文件的来源并更新它们。 对不起,我问你这个问题的方式(这是我今天醒来后做的第一件事)。无论如何,你几乎澄清了我对这个话题的所有疑问,非常感谢你的关注和支持。 @kvadityaaz:希望您可以通过.so 文件名识别它。也许它会很明显,或者搜索它会找到匹配项。否则,您可以将您的dependencies 复制到一个废品项目中,确认.so 出现在该废品项目的应用程序中,然后开始注释掉依赖项,直到您找到哪个拉入了.so 【参考方案1】:

根据 Google Play 团队发送的官方电子邮件,需要采取的措施是:

如果您还没有,我们鼓励您开始使用 64 位 尽快提出要求。许多应用程序完全用 非本地代码(例如 Java 编程语言或 Kotlin)和 不需要更改代码。

请注意,我们不会更改我们的 32 位政策 支持。 Google Play 将继续提供 32 位原生应用程序 代码到 32 位设备。该要求意味着这些应用程序将 还需要有 64 位版本。

为了帮助您完成过渡,我们准备了documentation 检查您的应用是否已经支持 64 位以及如何成为 64 位兼容。

我们还在下方提供了一个高级时间表。

所以,链接的文档说明:

如果您的应用仅使用以 Java 编程语言编写的代码,或者 Kotlin,包括任何库或 SDK,您的应用程序已经准备好 64 位设备。如果您的应用程序使用任何本机代码,或者您不确定是否 确实如此,您需要评估您的应用并采取行动。

[...]

检查 64 位库的最简单方法是检查 APK 文件的结构。构建后,APK 将与 应用程序所需的任何本机库。本机库存储在 基于 ABI 的各种文件夹。不需要支持每个 64 位架构,但对于每个本机 32 位架构,您 支持必须包含相应的 64 位架构。

对于 ARM 架构,32 位库位于 armeabi-v7a。 64 位等效版本是 arm64-v8a。

对于 x86 架构,请查找用于 32 位的 x86 和用于 32 位的 x86_64 64 位。

要做的第一件事是确保您在两者中都有本机库 这些文件夹。[...]

而且,要构建 64 位库,您基本上需要遵循以下说明:

大多数 Android Studio 项目都使用 Gradle 作为底层构建 系统,因此本节适用于这两种情况。启用构建 您的本机代码就像添加 arm64-v8a 和/或 x86_64 一样简单, 根据您希望支持的架构,到 应用程序的“build.gradle”文件中的 ndk.abiFilters 设置:

// Your app's build.gradle
apply plugin: 'com.android.app'

android 
   compileSdkVersion 27
   defaultConfig 
       appId "com.google.example.64bit"
       minSdkVersion 15
       targetSdkVersion 28
       versionCode 1
       versionName "1.0"
       ndk.abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
// ...

最后,一个简短的说明:

您的应用程序的 64 位版本应该提供相同的质量和 功能设置为 32 位版本。

顺便说一下,this official video 谈了一点。

【讨论】:

很好的答案,很有帮助。尽管我相信您的答案存在语法错误。 ndk.abiFilters = ... 不应有等号 =。我将编辑您的答案以删除它。希望你不要介意。顺便说一句,这个答案似乎证实不需要等号:***.com/a/54616385/1072150 没问题,@EJK,但我刚刚从their own documentartion 复制,它仍然声明:“ndk.abiFilters = 'armeabi-v7a' 'arm64-v8a' 'x86' 'x86_64”。有什么奇怪的!但是,由于此答案尚未对个人使用有用,因此我无法确认它是否适用于信号。 在最近的 Android Studio 版本中,ndk.abiFilters 'armeabi-v7a' 'arm64-v8a' 'x86' 'x86_64' 之间需要有逗号,如下所示:ndk.abiFilters 'armeabi-v7a', 'arm64-v8a'、'x86'、'x86_64' 完成,@whyoz。谢谢! 你找到解决办法了吗,@Debugger?【参考方案2】:

如果您没有本机 (NDK) 代码,即您只编写 Java/Dex 代码,那么您无需执行任何操作。

如果您有本机代码(或库),那么您需要提供它们的 64 位版本。

【讨论】:

如何提供 64 位版本?如果我的应用中有 ndk 确保按照NDK docs on this page 中的说明为 64 位目标进行编译。特别是 x86_64 如果你使用 x86 和 arm64-v8a 如果你使用 armeabi-v7a。【参考方案3】:

根据文档here,如果您的应用正在使用本机代码或外部库,例如基于本机的领域(如下图),则应提供对 64 位的支持。如果您的应用程序中使用任何 C/C++(本机)的任何外部库都应该同时支持 32 位和 64 位架构,否则您应该与库所有者联系。在 Android Studio 中,我们可以通过 Build > Analyze APK 检查两种架构的版本是否可用,并出现以下窗口:

如果您正在使用 NDK 并创建本机代码,则应通过在 gradle 中登记所有架构来提供对所有架构的支持:

defaultConfig   
   ndk.abiFilters = 'armeabi-v7a' 'arm64-v8a' 'x86' 'x86_64'
   

【讨论】:

我已经添加了这个,但是当我分析时,我只看到 armeabi-v7a & x86 而没有其他。有什么建议吗? 与@TusharGogna 相同...您解决了@Tushar 的问题吗? 您好,是的,我深入挖掘并发现第 3 方库之一(在我的情况下为 Here Maps)没有更新。该库没有 64 位支持。一旦我将它更新到最新版本,它就可以工作了。所以请确保所有 3rd 方库都更新到最新版本,然后重试。 @TusharGogna 有没有办法快速检查哪些库不支持 64 位?我有点困惑要检查什么.. :) 这是我的解决方案。我很困惑地看到 Google Play 抱怨 32 位代码,因为我自己没有使用任何本机代码,我的任何依赖项也没有(或者我认为)。当然,事实证明我的一个依赖项是向我的项目中传递地添加一个非常旧的 32 位版本的 sqlcipher。如果没有这个提示,永远不会找到它 - 谢谢!【参考方案4】:

如果您的 Android APK 不支持 64 位,您不必担心。 在 Android Studio 中转到构建 -> 分析 APK。您可以看到 APK 结构。在 lib 下,如果您看到 armeabi-v7a 库并且没有任何 arm64-v8ax86_64 库,那么您的 APK 不支持 64 位架构。

只需转到应用级别build.gradle 并在NDK 中的defaultConfig 下添加abiFilters,如下所示:

ndk 
    abiFilters 'armeabi-v7a','arm64-v8a','x86','x86_64'

【讨论】:

添加逗号为我节省了一天! 我试过了,但它仍然没有添加 64 位支持。我仍然只看到 'armeabi-v7a' 和 'x86' 有什么我错过了吗? 你能告诉我你的 build.gradle 文件中的 defaultConfig 块吗?【参考方案5】:

第 1 步:

app=> build.gradle (put below code in build.gradle)

android 
........

 defaultConfig 

 .........

   ndk 
            abiFilters = []
            abiFilters.addAll(PROP_APP_ABI.split(':').collectit as String)
        
........        

.......
 packagingOptions 
        exclude 'lib/armeabi-v7a/libARM_ARCH.so'
    


步骤:2

gradle.properties

(放在 gradle.properties 的下面一行)

PROP_APP_ABI=armeabi-v7a:arm64-v8a

第 3 步:再次构建项目。尝试将该 apk 上传到 Play 商店。

【讨论】:

【参考方案6】:

添加

ndk 
    abiFilters 'armeabi-v7a','arm64-v8a','x86','x86_64'
 

DefaultConfig 下的build.Gradle 文件中。请注意,推送播放存储 64 位要求即将到来。

【讨论】:

【参考方案7】:

我通过官方Android Docs 尝试了这个。工作出色。 在此解决方案中,我构建了多个 APK,您可以在附件中看到... 确保您的编译 Skd 版本是 29 或构建工具版本是 29.0.3 写在下面:

    Android 
    compileSdkVersion 29
    buildToolsVersion '29.0.3'
    
    defaultConfig 
        applicationId "com.myapp.sk"
        minSdkVersion 21
        targetSdkVersion 29
        versionCode 2
        versionName "1.0"
        multiDexEnabled true
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    
    
        splits 
            density 
                enable true
                reset()
                include "mdpi", "hdpi"
            
            abi 
                enable true
                reset()
                include "x86", "x86_64"
            
        
    

// Map for the version code that gives each ABI a value.
ext.abiCodes = ['armeabi-v7a':1, x86:2, x86_64:3]

// For per-density APKs, create a similar map like this:
// ext.densityCodes = ['mdpi': 1, 'hdpi': 2, 'xhdpi': 3]

import com.android.build.OutputFile

// For each APK output variant, override versionCode with a combination of
// ext.abiCodes * 1000 + variant.versionCode. In this example, variant.versionCode
// is equal to defaultConfig.versionCode. If you configure product flavors that
// define their own versionCode, variant.versionCode uses that value instead.
android.applicationVariants.all  variant ->

    // Assigns a different version code for each output APK
    // other than the universal APK.
    variant.outputs.each  output ->

        // Stores the value of ext.abiCodes that is associated with the ABI for this variant.
        def baseAbiVersionCode =
                // Determines the ABI for this variant and returns the mapped value.
                project.ext.abiCodes.get(output.getFilter(OutputFile.ABI))

        // Because abiCodes.get() returns null for ABIs that are not mapped by ext.abiCodes,
        // the following code does not override the version code for universal APKs.
        // However, because we want universal APKs to have the lowest version code,
        // this outcome is desirable.
        if (baseAbiVersionCode != null) 

            // Assigns the new version code to versionCodeOverride, which changes the version code
            // for only the output APK, not for the variant itself. Skipping this step simply
            // causes Gradle to use the value of variant.versionCode for the APK.
            output.versionCodeOverride =
                    baseAbiVersionCode * 1000 + variant.versionCode
        
    

Multi-Aks Attachment

【讨论】:

【参考方案8】:

本机代码:是指直接编译为运行它的计算机的 CPU 指令的可执行程序。

非本机代码:是指编译为 1970 年代末和 1980 年代原始 Tandem 架构的 CPU 指令的可执行程序。当这样的程序运行时,它不能直接在运行它的计算机的 CPU 上执行。 NonStop 操作系统包含一个原始 Tandem 架构的解释器,用于运行此类非本地代码。

如果您的应用仅使用以 Java 编程语言或 Kotlin 编写的代码,包括任何库或 SDK,则您的应用已经准备好用于 64 位设备。如果您的应用使用任何本机代码,或者您不确定是否使用,则需要评估您的应用并采取行动。

您的应用是否使用本机代码?

首先要做的是检查您的应用是否使用任何本机代码。如果满足以下条件,您的应用会使用本机代码:

在您的应用中使用任何 C/C++(本机)代码。 与任何第三方原生库的链接。 由使用本机库的第三方应用构建器构建。

更多信息,visit the docs。

【讨论】:

【参考方案9】: 选项 1 - 从 APK 中删除 lib。 步骤 1 - 将 APK 转换为 ZIP 并找到 lib 文件夹;如果你有 lib 文件夹,请查看库依赖项。 第 2 步 - 从构建 Gradle 中删除依赖项。 选项 2 - 下载 64 位和 32 位 JAR 文件并添加到应用程序中的 lib 文件夹并构建。

【讨论】:

我正在尝试xWalkCorelibrary,但不幸的是它提供了 32 个 64 位独立的 .aar 文件,当我添加这两个文件时,它给了我重复的库,你能帮我吗? 您需要下载xWalkCore jar文件并添加到您的项目模块中 是的,我已经添加了。它分别提供 32 位和 64 位库,当我将这两个库添加到我的项目中时,它可以在调试模式下工作,但是当我创建符号 apk 时,它会显示重复文件错误 压缩然后解压 Apk 文件,显示重复的库【参考方案10】:

首先打开 build.gradle 模块应用程序并添加这些行以删除 .so 文件并添加 64 位库 删除存在于 apk 库中的所有 .so 文件

android     
    compileSdkVersion 29    
    defaultConfig     
        -----    
        -----    
        ndk.abiFilters 'armeabi-v7a','arm64-v8a','x86','x86_64'    
        ndk     
            abiFilters 'armeabi-v7a','arm64-v8a','x86','x86_64'    
            
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"    
        
packagingOptions     
        packagingOptions     
            exclude 'lib/armeabi-v7a/libvudroid.so'    
            exclude 'lib/x86/libvudroid.so'    
            exclude 'lib/arm64-v8a/libvudroid.so'    
            
    `

【讨论】:

【参考方案11】:

就我而言,我使用的是一个使用 OpenGL C 库的库(ESRI ArcGIS for Android)。而不是 ndk.abiFilters... 似乎可以解决其他所有人问题的字符串,我不得不使用以下内容:

ndk abiFilters "armeabi-v7a", "arm64-v8a"

【讨论】:

【参考方案12】:

在你的 build.gradle 中添加这个

ndk.abiFilters 'arm64-v8a','x86_64'

【讨论】:

以上是关于如何制作同时支持 32 位和 64 位架构的 Android 应用程序?的主要内容,如果未能解决你的问题,请参考以下文章

如何在同时拥有 64 位和 32 位版本的同时安装 64 位软件包?

当同时安装 32 位和 64 位 JVM 时,如何使用 32 位 JVM 强制运行 Jar 文件?

32位和64位有啥区别 32位和64位区别都有哪些

在 .NET 项目中同时引用 32 位和 64 位 dll 并单击一次 [重复]

如何在64位windows7上同时使用32位和64位的Eclipse

电脑32位和64位有啥区别 电脑32位和64位的区别