如何制作同时支持32位和64位架构的安卓应用?

回答 12 浏览 6.6万 2018-01-31

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

对于那些还没有读过的人来说,它指出。

2019年的64位支持要求

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

由于预计未来的安卓设备只支持64位代码,Play控制台将要求新的应用程序和带有本地库的应用程序更新在其32位版本之外提供64位版本。这可以是在单个APK内,也可以是作为发布的多个APK中的一个。

我们并没有取消对32位的支持。Google Play将继续支持32位应用程序和设备。不包括本地代码的应用程序不受影响。

这一变化将于2019年8月生效。我们今天提供了提前通知,以便让那些尚未支持 64 位的开发者有足够的时间来计划过渡。请继续关注我们未来的文章,我们将深入研究Android上64位本地库的性能优势,并查看NDK的CPU和架构指南以了解更多信息。

在适用的情况下,我们需要做出哪些实际的改变来完美地遵守这一新的要求?

JorgeAmVF 提问于2018-01-31
如果您有自己的 NDK 代码,它将需要支持 64 位版本的 ABI。如果您没有自己的NDK代码,但您使用的是有NDK代码的库,那么他们将需要提供支持64位CPU架构的库版本。CommonsWare 2018-01-31
感谢您的回答,CommonsWare!从你的回答和我读到的东西来看,这似乎并不复杂。只是让我再问你一件事:如果开发者既不拥有也不使用NDK代码,是否意味着普通应用程序已经可以使用这两种代码了?另外,如果你愿意把文字作为答案交付给我,我很乐意接受它,请放心。JorgeAmVF 2018-02-01
"如果开发者既不拥有也不使用NDK代码,是否意味着普通应用程序已经可以使用这两种代码了?"-- 因为我不确定你说的 "既不拥有也不使用 "是什么意思,所以我不能回答这个问题,抱歉。换个说法:如果你检查你的APK(例如,在Android Studio中分析APK),你没有发现包含.so文件的lib/目录,那么对于这个即将到来的要求,你不需要做什么。如果你找到.so文件,并且在名册中没有看到64位架构,你需要找到这些.so文件的来源并更新它们。CommonsWare 2018-02-01
很抱歉我向你提问的方式(这是我今天醒来后做的第一件事)。无论如何,你实际上澄清了我对这个问题的所有疑虑,我非常感谢你的关注和支持。JorgeAmVF 2018-02-01
@kvadityaaz。希望你能通过.so文件名来识别它。也许这很明显,或者搜索一下就能找到一个匹配的。否则,你可以把你的dependencies复制到一个废弃的项目中,确认.so出现在该废弃项目的应用程序中,然后开始注释依赖关系,直到你发现哪个依赖关系拉到了.soCommonsWare 2019-08-25
12 个回答
#1楼 已采纳
得票数 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架构,32位的要看x86,64位的要看x86_64。

首先要做的是确保你在这两个文件夹中都有本机库,[...] 。

而且,要构建64位库,你基本上需要按照下面的指示来做。

大多数 Android Studio 项目使用 Gradle 作为底层构建系统,因此本节适用于这两种情况。为你的本地代码启用构建,就像在你的应用程序的'build.gradle'文件中的ndk.abiFilters设置中加入arm64-v8a和/或x86_64(取决于你希望支持的架构)一样简单。

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

顺便说一下,这个官方视频谈了一点。

JorgeAmVF 提问于2019-02-01
JorgeAmVF 修改于2019-08-26
很好的回答,非常有帮助。虽然我认为你的答案中有一个语法错误。ndk.abiFilters = ...不应该有一个等号=。我将编辑你的答案,删除这一点。希望你不要介意。BTW,这个答案似乎证实了不需要等号的说法。stackoverflow.com/a/54616385/1072150EJK 2019-02-21
没问题,@EJK,但我刚刚从他们自己的文档中复制了,其中仍然写着。"ndk.abiFilters = 'armeabi-v7a' 'arm64-v8a' 'x86' 'x86_64".真是奇怪!不过,由于这个答案对个人使用还没有用处,我无法确认它是否能与信号一起使用。JorgeAmVF 2019-02-21
在最近的Android Studio构建中,ndk.abiFilters 'armabi-v7a' 'arm64-v8a' 'x86' 'x86_64'之间需要有逗号,像这样:ndk.abiFilters 'armabi-v7a', 'arm64-v8a', 'x86', 'x86_64' 。whyoz 2019-08-02
完成了,@whyoz。谢谢!JorgeAmVF 2019-08-02
你是否找到了解决方法,@Debugger?JorgeAmVF 2019-09-29
#2楼
得票数 13

如果你没有本地(NDK)代码,也就是你只写Java/Dex代码,那么你就不需要做任何事情。

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

Nick Fortescue 提问于2018-02-02
JorgeAmVF 修改于2019-01-31
如果我的应用程序中有ndk,我怎样才能提供64位的版本?Ajay Pandya 2019-04-13
请确保您按照本页NDK 文档中的描述,为 64 位目标进行编译。如果您使用 x86,特别是 x86_64,如果您使用 armeabi-v7a,特别是 arm64-v8a。Nick Fortescue 2019-04-15
#3楼
得票数 11

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

如果你使用NDK并创建本地代码,你应该通过在gradle中列举它们来提供对所有体系结构的支持。

defaultConfig {  
   ndk.abiFilters = 'armeabi-v7a' 'arm64-v8a' 'x86' 'x86_64'
   }
Irfan Ul Haq 提问于2019-03-05
Irfan Ul Haq 修改于2020-03-31
我已经添加了这个,但当我分析时,我只看到armeabi-v7a和x86,而不是其他。有什么建议吗?Tushar Gogna 2019-08-02
与@TusharGogna一样 ...你解决了你的问题吗 @Tushar?mboy 2019-08-10
你好,是的,我深入调查了一下,发现其中一个第三方库(在我的例子中是Here Maps)没有更新。该库不支持64位。一旦我把它更新到最新版本,它就能工作了。所以,请确保所有的第三方软件都更新到最新版本,然后再试一次。Tushar Gogna 2019-08-10
@TusharGogna 有什么方法可以快速检查哪些库不支持64位?我有点困惑,不知道该怎么检查... :)mboy 2019-08-10
这就是我的解决方案。当我看到 Google Play 抱怨 32 位代码时,我感到很困惑,因为我自己没有使用任何本地代码,我的任何依赖也没有(我是这么认为的)。当然,事实证明,我的一个依赖项在我的项目中加入了一个非常老的32位版本的sqlcipher。如果没有这个提示,我永远也不会发现它--谢谢!Luke Needham 2021-01-08
#4楼
得票数 7

如果你的安卓APK不包括64位支持,你不必担心。 在安卓工作室中,进入构建->分析APK。你可以看到APK结构。在lib下,如果你看到armeabi-v7a库,如果你没有任何arm64-v8ax86_64库,那么你的APK不支持64位架构。

只要进入应用层build.gradle,在NDK的defaultConfig下添加abiFilters即可,如下所示:

ndk {
    abiFilters 'armeabi-v7a','arm64-v8a','x86','x86_64'
}
sagarchavan 提问于2019-07-11
JorgeAmVF 修改于2019-07-12
加逗号救了我一命!whyoz 2019-08-02
我试了一下,仍然没有添加64位的支持。我仍然只看到'armabi-v7a'和'x86',有什么我漏掉的吗?mboy 2019-08-10
你能不能给我看看你的build.gradle文件中的defaultConfig块?sagarchavan 2019-08-12
#5楼
得票数 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步: 2

gradle.properties

(把下面一行放在gradle.properties中)

PROP_APP_ABI=armeabi-v7a:arm64-v8a

第3步:再次构建propject。尝试将该apk上传至Play Store。

Girly Android Developers 提问于2020-06-13
#6楼
得票数 2

添加

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

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

nidamanuri chandu 提问于2019-09-09
B--rian 修改于2019-09-09
#7楼
得票数 2

我通过官方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
        }
    }
}

多问句附件

SyKo 提问于2020-07-31
#8楼
得票数 1

原生代码:指的是直接根据所运行的计算机的CPU指令编译的可执行程序。

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

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

您的应用程序是否使用了原生代码?

首先要做的是检查您的应用程序是否使用任何本地代码。如果你的应用程序使用了本机代码,那么它就会使用。

  • 在你的应用程序中使用任何C/C++(本机)代码。
  • 与任何第三方本机库的链接。
  • 由使用本地库的第三方应用程序生成器构建。

更多信息,请访问文档

EL TEGANI MOHAMED HAMAD GABIR 提问于2019-07-04
EL TEGANI MOHAMED HAMAD GABIR 修改于2019-07-13
#9楼
得票数 1
    选项 1 - 从 APK 中删除 lib。
  • 第一步 - 将 APK 转换为 ZIP 并找到 lib 文件夹;如果你有 lib 文件夹,请查看库依赖项。
  • 第2步--从构建Gradle中移除依赖性。
  • 选项 2 - 下载 64 位和 32 位 JAR 文件并添加到应用程序的 lib 文件夹中并构建。
  • Vibhu Vikram Singh 提问于2019-08-21
    B--rian 修改于2019-09-09
    我正在尝试xWalkCore库,但不幸的是,它提供了32位和64位的独立.aar文件,当我添加这两个文件时,它给了我重复的库,你能帮助我吗?Sultan Ali 2019-09-19
    您需要下载xWalkCore jar文件,并在您的项目中添加模块。Vibhu Vikram Singh 2019-09-19
    是的,我已经添加了它。它分别提供了32位和64位的库,当我把这两个库添加到我的项目中时,它在调试模式下工作,但当我创建一个符号apk时,它显示了重复文件的错误。Sultan Ali 2019-09-20
    压缩,然后解压缩Apk文件,显示重复的库。Vibhu Vikram Singh 2020-01-30
    #10楼
    得票数 1

    首先打开build.gradle模块应用程序并添加这些行,以便删除.so文件并添加64位liobraries,删除apk的libs中存在的所有.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'    
            }    
        }`
    
    Hemanths 提问于2020-05-05
    #11楼
    得票数 1

    在我的案例中,我使用的是一个利用OpenGL C库的库(ESRI ArcGIS for Android)。我没有使用似乎可以解决其他人问题的ndk.abiFilters...字符串,而是使用了以下内容:

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

    Chris Stillwell 提问于2020-05-13
    #12楼
    得票数 1

    在你的build.gradle中添加此内容

    ndk.abiFilters 'arm64-v8a','x86_64'
    
    eagerprince 提问于2020-08-22
    Bhargav Rao 修改于2020-09-13