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

38

我刚刚收到并阅读了来自Google Play的新闻通讯, 其中提到从明年开始,商店“将要求具有本地库的新应用程序和应用程序更新除其32位版本外还提供64位版本”。

对于那些还没有阅读过的人,它声明:

2019年的64位支持要求
Android 5.0引入了对64位架构的平台支持。今天,超过40%的上线Android设备支持64位,同时仍保持32位兼容性。对于使用本机库的应用程序,64位代码通常具有更好的性能,具有额外的寄存器和新的指令。
为了预期支持仅支持64位代码的未来Android设备,Play Console将要求提供本地库的新应用程序和应用程序更新除其32位版本外还提供64位版本。这可以在单个APK内或作为发布的多个APK之一。
我们不会删除32位支持。Google Play将继续支持32位应用程序和设备。不包括本地代码的应用程序不受影响。
此更改将于2019年8月生效。我们今天提供先进通知,以便给尚未支持64位的开发人员充分的时间来计划过渡。敬请关注我们未来的帖子,我们将深入研究Android上64位本地库的性能优势,并查看NDK的CPU和架构指南获取更多信息。
当适用时,我们需要进行哪些实际更改才能完全遵守这项新要求?

5
如果您拥有自己的 NDK 代码,它将需要支持 64 位版本的 ABIs。如果您没有自己的 NDK 代码,但是您正在使用具有自己代码的库,则这些库将需要提供支持 64 位 CPU 架构的库版本。 - CommonsWare
感谢您的回答,CommonsWare!根据您的回答和我所读到的内容,似乎并不那么复杂。只是让我再问您一件事:如果开发人员既不拥有也不使用NDK代码,这是否意味着常规应用程序已经准备好同时支持两者?此外,如果您想将文本作为答案提供,我很乐意接受。 - JorgeAmVF
2
如果开发者既不拥有也不使用NDK代码,那么这是否意味着常规应用程序已经准备好支持64位架构?由于我不确定您所说的“既不拥有也不使用”的含义,因此无法回答。换句话说:如果您检查您的APK文件(例如,在Android Studio中分析APK),并且您没有找到包含“.so”文件的“lib/”目录,则无需对即将推出的要求做任何处理。如果您发现“.so”文件,并且在名单中没有看到64位架构,则需要找到这些“.so”文件的源并进行更新。 - CommonsWare
抱歉我之前提问的方式有些不妥(那是我今天一起床就做的第一件事)。无论如何,你已经几乎解决了我关于这个主题的所有疑惑,非常感谢你的关注和支持。 - JorgeAmVF
我如何知道哪个依赖项含有那个.so文件@CommonsWare - kvadityaaz
1
@kvadityaaz:希望您能通过.so文件名来识别它。也许很明显,或者通过搜索可能找到一个匹配项。否则,您可以将dependencies复制到一个废弃项目中,并确认.so文件出现在该废弃项目的应用程序中,然后逐个注释掉依赖项,直到找到哪个依赖项引入了.so - CommonsWare
12个回答

27
根据Google Play团队发送的官方电子邮件,所需的操作是:
如果您尚未开始工作以满足64位要求,我们鼓励您尽快开始。许多应用程序完全使用非本地代码(例如Java编程语言或Kotlin)编写,并且不需要更改代码。
请注意,我们不会更改关于32位支持的政策。 Google Play将继续向32位设备提供具有32位本机代码的应用程序。该要求意味着这些应用程序也需要具有64位版本。
为了帮助您过渡,我们已准备好文档,说明如何检查您的应用程序是否已支持64位以及如何符合64位标准。
我们还提供了一个高级时间表。
因此,链接的文档解释了:
如果你的应用程序仅使用Java编程语言或Kotlin编写的代码,包括任何库或SDK,则你的应用程序已经准备好支持64位设备。如果你的应用程序使用任何本地代码,或者你不确定是否使用了本地代码,那么你需要评估你的应用程序并采取行动。
检查64位库最简单的方法是检查APK文件的结构。构建时,APK将打包与应用程序所需的任何本地库。本地库存储在基于ABI的各个文件夹中。不需要支持每个64位架构,但对于每个本机32位架构,你必须包含相应的64位架构。
对于ARM架构,32位库位于armeabi-v7a。相应的64位库是arm64-v8a。
对于x86架构,请查找x86以获取32位和x86_64以获取64位。
首先要做的是确保这两个文件夹中都有本地库。要构建64位库,你基本上需要按照以下说明操作:

Most Android Studio projects use Gradle as the underlying build system, so this section applies to both cases. Enabling builds for your native code is as simple as adding the arm64-v8a and/or x86_64, depending on the architecture(s) you wish to support, to the ndk.abiFilters setting in your app's 'build.gradle' file:

// 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位版本相同的质量和功能集。

顺便说一下,这个官方视频稍微谈了一下这个问题。


1
非常好的答案,非常有帮助。虽然我认为你的答案中有一个语法错误。ndk.abiFilters = ...不应该有等号=。我将编辑您的答案以删除此内容。希望您不介意。顺便说一下,这个答案似乎证实了不需要等号:https://stackoverflow.com/a/54616385/1072150 - EJK
没问题,@EJK,但我只是从他们自己的文件中复制而来,其中仍然提到:“ndk.abiFilters = 'armeabi-v7a' 'arm64-v8a' 'x86' 'x86_64”。这很奇怪!然而,由于这个答案对个人使用还没有用处,所以我无法确认它是否与Signal一起使用。 - JorgeAmVF
1
在最近的Android Studio版本中,ndk.abiFilters 'armeabi-v7a' 'arm64-v8a' 'x86' 'x86_64' 需要像这样之间加上逗号:ndk.abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'。 - whyoz
你找到了解决方法了吗,@Debugger? - JorgeAmVF
是的,我找到了@JorgeAmVF。 - mob_web_dev
显示剩余2条评论

13

如果您没有使用本地代码(NDK),也就是说,您只编写Java/Dex代码,则无需进行任何操作。

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


2
如果我的应用程序中有 NDK,我该如何提供 64 位版本? - Ajay Pandya
1
请确保按照此页面上的NDK文档所述,为64位目标编译。如果使用x86,请选择x86_64;如果使用armeabi-v7a,请选择arm64-v8a。 - Nick Fortescue

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

Android Studio tab showing available architectures

如果你使用NDK并创建本地代码,应该通过在gradle中列出所有架构来为它们提供支持:

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

4
我已添加了这个,但在分析时只看到 armeabi-v7a 和 x86,没有其他的。有什么建议吗? - Tushar Gogna
1
和 @TusharGogna 一样...你解决了吗,@Tushar? - mboy
3
你好,是的,我深入研究后发现我的其中一个第三方库(在这种情况下是Here地图)没有更新。该库不支持64位。一旦我将其更新到最新版本,就可以正常工作了。因此,请确保所有第三方库均已更新至最新版本,然后再尝试一次。 - Tushar Gogna
2
@TusharGogna 是否有一种快速检查不支持64位的库的方法?我有点困惑该检查什么.. :) - mboy
这对我来说是解决方案。我很困惑,因为我没有使用任何本地代码,我的依赖项也没有使用(至少我认为如此),但是谷歌Play仍然抱怨32位代码。当然,结果发现我的一个依赖项在传递时向我的项目添加了一个非常旧的32位版本的sqlcipher。如果没有这个提示,我永远不会发现它-谢谢! - Luke Needham

7
如果您的Android APK不包含64位支持,无需担心。在Android Studio中,转到“Build -> Analyze APK”,您可以查看APK结构。如果在lib下看到armeabi-v7a库而没有arm64-v8ax86_64库,则您的APK不支持64位架构。
只需进入应用级别的build.gradle,并在defaultConfig下的NDK中添加abiFilters,如下所示:
ndk {
    abiFilters 'armeabi-v7a','arm64-v8a','x86','x86_64'
}

1
添加逗号为我解决了大问题! - whyoz
1
我尝试了这个方法,但仍然没有添加64位支持。我仍然只看到'armeabi-v7a'和'x86'。我有什么遗漏吗? - mboy
请问您能否展示您的 build.gradle 文件中的 defaultConfig 块? - sagarchavan

4

步骤1:

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

android {
........

 defaultConfig {

 .........

   ndk {
            abiFilters = []
            abiFilters.addAll(PROP_APP_ABI.split(':').collect{it as String})
        }
........        
}
.......
 packagingOptions {
        exclude 'lib/armeabi-v7a/libARM_ARCH.so'
    }

}

步骤:2

gradle.properties

(将以下内容放入gradle.properties文件中)

PROP_APP_ABI=armeabi-v7a:arm64-v8a

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


2

添加

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

DefaultConfig下的build.Gradle文件中。请注意,推送到Play商店的64位要求即将到来。

2
我尝试了官方的Android文档,效果非常好。 在这个解决方案中,我构建了多个APK,您可以在附件中查看... 请确保您的编译SDK版本为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
        }
    }
}

多轴附件

(注:此为产品名称,无需翻译)

1

本地代码:指编译成可执行程序直接运行在计算机 CPU 指令上的程序。

非本地代码:指编译成可执行程序运行在 1970 年代末和 1980 年代 Tandem 架构的 CPU 指令上的程序。当此类程序运行时,无法直接在计算机 CPU 上执行。NonStop 操作系统包括一个解释器,用于运行这种非本地代码。

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

您的应用程序是否使用本地代码?

首先要做的是检查您的应用程序是否使用任何本地代码。如果您的应用程序:

  • 在应用程序中使用了任何 C/C++(本地)代码。
  • 链接到任何第三方本地库。
  • 由使用本地库的第三方应用程序构建器构建。
更多信息,请访问文档

1
  • 选项1 - 从APK中删除库。
    • 步骤1 - 将APK转换为ZIP并找到lib文件夹;如果您有lib文件夹,请查看库依赖关系。
    • 步骤2 - 从构建Gradle中删除依赖项。
  • 选项2 - 下载64位和32位JAR文件并添加到应用程序的lib文件夹中并进行构建。

我正在尝试使用xWalkCore库,但不幸的是它提供了32位和64位分开的.aar文件,当我添加这两个文件时会出现重复库的问题,你能帮我吗? - Sultan Ali
您需要下载xWalkCore jar文件,并将其添加到您的项目模块中。 - Vibhu Vikram Singh
是的,我已经添加了它。它提供32位和64位库,并且当我将这两个库添加到我的项目中时,它可以在调试模式下工作,但是当我创建签名“apk”时,它会显示重复文件错误。 - Sultan Ali
压缩并解压Apk文件,显示重复的库。 - Vibhu Vikram Singh

1
在你的 build.gradle 文件中添加这个。
ndk.abiFilters 'arm64-v8a','x86_64'

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接