android预编译apk的深入思考

有时候我们会去和别的客户合作开发一些项目,但是出于安全性的考虑,独立的模块我们不会发布源码,只会以apk或者so的形式release给客户。

合作的时候我们这边的apk release给用户,但是客户编译的OTA包运行起来后此apk开机会挂掉,提示找不到jni,但去单板的对应目录去查看发现此jni的so是存在的,比较奇怪。

Line 60: E/AndroidRuntime( 4751): java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/system/app/xxxxGuide/xxxxGuide.apk"],nativeLibraryDirectories=[/vendor/lib64, /system/lib64]]] couldn't find "libxxxxjni.so"
    Line 95: E/AndroidRuntime( 4782): java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/system/app/xxxxxService/xxxxxService.apk"],nativeLibraryDirectories=[/vendor/lib64, /system/lib64]]] couldn't find "libxxxxjni.so"

询问高手后,给出的结论是:
从log看,这些apk加载so出错了。这些apk是不是没有按照系统标准编译来编啊?
如果是源码,一定要通过Android.mk来编译,如果是release的apk文件,也需要通过Android.mk来预编译。不能把eclipse或者AndroidStudio中的apk直接拖过来用。

但是自己还是不太理解,回顾此apk的编译方式,发现此apk是编译时直接cp apk到out目录的。此apk运行的时候会间接的通过java接口依赖到此jni so上去,而cp apk到out目录打包到OTA包的时候会破坏apk的运行查找规则,需要手动建立依赖关系才行。手动建立依赖关系需要通过预编译来实现。

具体分析:
开机的时候 xxxxxService的apk会跑到lib64下去找libxxxjni的so找不到报错,而我们的apk是32位的,只允许去32库下去查找。
—因为从Android5.0之后,Android从32位升级到64位系统
ps查看zygote进程是32和64共存,

ps |grep zygote                                        
root      1564  1     2066844 89296 ffffffff a6675f44 S zygote64
root      1565  1     1478752 76004 ffffffff f72066e8 S zygote

如果一个apk的部分方法有依赖jni so的话,在编译的时候需要指定此apk是32位的还是64位,如果不指定就会默认去64位lib下去找;
1、用源码编译的时候在Android.mk中指定

LOCAL_JNI_SHARED_LIBRARIES := libxxxxjni
LOCAL_MULTILIB := 32

编译出来的out目录下apk文件夹中会创建arm/lib目录,去此目录下ll查看可看的有软链接
libxxxxjni.so -> /system/lib/libxxxxjni.so,但去Samba去查看的时候此文件夹为空;
2、如果不用源码编译,在代码编译的时候只放apk,在编译的时候只做拷贝到out目录的动作
–这样会导致我们最初遇到的错误,寻找so报错,因为我们手动破坏了apk和so的链接关系,所以要做apk的预编译来重新建立软链接;
–方法是在apk的目录下创建Android.mk文件,
例如:

include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := xxxxxService
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
LOCAL_CERTIFICATE := platform
LOCAL_SRC_FILES := xxxxxService.apk 
LOCAL_JNI_SHARED_LIBRARIES := libxxxxjni
LOCAL_MULTILIB := 32
LOCAL_MODULE_PATH := $(TARGET_OUT_APPS)
include $(BUILD_PREBUILT)

这样编译生成的out目录下apk文件夹中就会有arm/lib的文件夹,apk和so的软链接关系存在正常。
或者加入LOCAL_32_BIT_ONLY := true这句话,指定此apk只用32位,这样编译的apk默认为32位,编译生成的out目录下的此apk文件夹不会创建arm/lib目录。

通过第二种方式重新预编译后,apk运行正常。

你可能感兴趣的:(Android)