Android NDK and Google Play filtering

2019-02-05 04:18发布

问题:

The Google Play appstore automatically filters your application to devices with compatible CPU architecture. E.g. if you have a library which is only compiled for ARMv5, your app will only show up for devices with ARMv5 or ARMv7 processors.

What if I have a Java alternative, and want my app to be downloaded by non-ARM devices too? E.g. I catch an exception when trying to load the external library, and implement a workable alternative in Dex bytecode (Java).

When I upload the .apk, the Android Developer Console says: "This apk requests 1 native platforms that will be used for Google Play filtering. armeabi"

Do I need to compile dummy libraries for x86 and MIPS? Then in my Java code, check the processor architecture to know if I can actually use the library? There should be a better solution.

As far as I know, there is nothing in the Manifest about CPU architecture, and I cannot find a way in the Developer Console to turn this filter off.

Hopefully somebody who knows a lot more than I do about Google Play filtering and the NDK knows the answer.

回答1:

While trapping for loadLibrary failures will work on any device (at least all that I have tried including GTVs), but the Play Store will not show on devices if the ABI for that platform does not exist in the apk.

From the docs ( http://developer.android.com/guide/appendix/market-filters.html ): An application that includes native libraries that target a specific platform (ARM EABI v7 or x86, for example) are visible only on devices that support that platform.

In in theory, building for all platforms would be able to target all devices, but in practice there are some devices like Google Tv that report no ABI, which means that only apks that have no native code will appear in the Play Store on those devices. You can use multiple apks, however, 1 with no native code and 1 with all platforms that support your native code.

You can read about multiple apk support here: http://developer.android.com/guide/market/publishing/multiple-apks.html



回答2:

There's a very complete answer to this same question here : http://grokbase.com/t/gg/android-ndk/125v31e6wy/play-store-market-filtering-of-ndk-libs

Let me post my own solution, it's almost the same I've posted here : Android library .so with x86 architecture missing? (Vuforia)

So you have a regular Android.mk that can't compile on x86 architecture because the library (libExternalLibrary.so) you're using is only provided for the arm archi. You want to build a .so (libMyLibraryBasedOnExternalLibrary.so) based on this library, and of course it won't never compile on x86 without the library.

The idea is to generate Dummy libraries for x86 directly directly in the Android.mk, using conditional compilation instructions.

1) Create 2 dummy .cpp files Dummy0.cpp and Dummy1.cpp exemple Dummy0.cpp looks like this :

#include <jni.h>
#include <android/log.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <math.h>
#include <string>

#ifdef __cplusplus
extern "C"
{
#endif

int dummy0                        =  0;

#ifdef __cplusplus
}
#endif

Then, edit the Android.mk that builds your library and modify it like this :

LOCAL_PATH := $(call my-dir)

ifeq ($(TARGET_ARCH_ABI), armeabi)


# In this condtion block, we're compiling for arm architecture, and the libExternalLibrary.so is avaialble
# Put every thing the original Android.mk was doing here, importing the prebuilt library, compiling the shared library, etc...
# ...
# ...

else

# In this condtion block, we're not compiling for arm architecture, and the libExternalLibrary.so is not availalble.
# So we create a dummy library instead.

include $(CLEAR_VARS)
# when LOCAL_MODULE equals to ExternalLibrary, this will create a libExternalLibrary.so, which is exactly what we want to do.
LOCAL_MODULE := ExternalLibrary
LOCAL_SRC_FILES := Dummy0.cpp
include $(BUILD_SHARED_LIBRARY)

include $(CLEAR_VARS)
# This will create a libMyLibraryBasedOnExternalLibrary.so
LOCAL_MODULE := MyLibraryBasedOnExternalLibrary
# Don't forget to tell this library is based on ExternalLibrary, otherwise libExternalLibrary.so will not be copied in the libs/x86 directory
LOCAL_SHARED_LIBRARIES := ExternalLibrary
LOCAL_SRC_FILES := Dummy1.cpp
include $(BUILD_SHARED_LIBRARY)

endif

Of course, make sure in your code that you never call the library when your app is running on a x86 only device :

if ((android.os.Build.CPU_ABI.equalsIgnoreCase("armeabi")) || (android.os.Build.CPU_ABI2.equalsIgnoreCase("armeabi"))) {
    // Good I can launch
    // Note that CPU_ABI2 is api level 8 (v2.2)
    // ...
}