欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

android 系统应用签名及问题处理

程序员文章站 2022-03-25 08:22:54
在做系统级的APP开发时,我们就会给app签名。这个不是我们通常的签名打包,有所不同。要拿到的两个文件platform.x509.pem,platform.pk8它们存放在系统的/build/target/product/security/目录下,当然这个是要你对应的android系统开发提供的,拿到这两个文件后就可以做我们的app签名了。当然你可以cmd签名方式生成apk,后面会说项目需要添加的东西,这里先跳过。只需要这个两个文件的文件夹下,打开终端切换到这个路径输入(xxx为你放入你打包的apk,...

在做系统级的APP开发时,我们就会给app签名。这个不是我们通常的签名打包,有所不同。要拿到的两个文件platform.x509.pem,platform.pk8它们存放在系统的/build/target/product/security/目录下,当然这个是要你对应的android系统开发提供的,拿到这两个文件后就可以做我们的app签名了。

当然你可以cmd签名方式生成apk,后面会说项目需要添加的东西,这里先跳过。
只需要这个两个文件的文件夹下,打开终端切换到这个路径输入(xxx为你放入你打包的apk,XXXNew是你生成的apk名称)
java -jar signapk.jar platform.x509.pem platform.pk8 XXX.apk XXXNew.apk
这个就能生成你的签名系统应用包了。

但是这样不方便我们打包,也不能使用jenkins自动打包。下面我要说的就是生成一个keystore签名文件。来实现系统应用签名。
1.下载keytool工具。和上面两个文件放在同一目录下。

sh keytool-importkeypair -k ./platform.keystore -p android -pk8 platform.pk8 -cert platform.x509.pem -alias platform
  • -p 表示新生成的keystore的密码是什么,这里为android
  • -pk8 表示要导入的pk8文件的名称,可以包括路径,pk8文件用来保存private key的,是个私钥文件。
  • -cert 表示要导入的证书文件,和pk8文件在同一个目录,pem这种文件就是一个X.509的数字证书,里面有用户的公钥等信息,是用来解密的,这种文 件格式里面不仅可以存储数字证书,还能存各种key。(有兴趣的可以点击此了解一下
  • -alias 表示给生成的platform.keystore取一个别名,这个名字只有我们在签名的时候才用的到,这里我们生成的文件名是platform。这个名字,可以随便取,但是你自己一定要记住。

2.AndroidManifest.xml修改

AndroidManifest.xml中添加共享系统进程属性,如下:

android:sharedUserId="android.uid.system"
android:sharedUserId="android.uid.shared"
android:sharedUserId="android.media"

根据自己需求添加,因为我们测试验证用的是platform的,所以在xml中添加的是android:sharedUserId="android.uid.system"。

 到这里如果你没有用到webview基本就只是前签名文件的配置就可以了

当然一般项目都会用到。那么就签名成功后的apk,当你加载webview时候就报应用闪退。

java.lang.UnsupportedOperationException: For security reasons, WebView is not allowed in privileged processes

你会看到这样的报错信息。

See android 5.1 source code below

static WebViewFactoryProvider getProvider() {
    synchronized (sProviderLock) {
        // For now the main purpose of this function (and the factory abstraction) is to keep
        // us honest and minimize usage of WebView internals when binding the proxy.
        if (sProviderInstance != null) return sProviderInstance;

        final int uid = android.os.Process.myUid();
        if (uid == android.os.Process.ROOT_UID || uid == android.os.Process.SYSTEM_UID) {
        throw new UnsupportedOperationException(
            "For security reasons, WebView is not allowed in 
privileged processes");
        }

...

 Android do such security check during creating WebViewFactory's field sProviderInstance(when it is null), and sProviderInstance is a static field. So we can make a instance of sProviderInstance before the security check by using reflection.

不同android版本的源码有所不用,需要用反射做下兼容处理。

public static void hookWebView(){
        int sdkInt = Build.VERSION.SDK_INT;
        try {
            Class<?> factoryClass = Class.forName("android.webkit.WebViewFactory");
            Field field = factoryClass.getDeclaredField("sProviderInstance");
            field.setAccessible(true);
            Object sProviderInstance = field.get(null);
            if (sProviderInstance != null) {
                Log.i(TAG,"sProviderInstance isn't null");
                return;
            }

            Method getProviderClassMethod;
            if (sdkInt > 22) {
                getProviderClassMethod = factoryClass.getDeclaredMethod("getProviderClass");
            } else if (sdkInt == 22) {
                getProviderClassMethod = factoryClass.getDeclaredMethod("getFactoryClass");
            } else {
                Log.i(TAG,"Don't need to Hook WebView");
                return;
            }
            getProviderClassMethod.setAccessible(true);
            Class<?> factoryProviderClass = (Class<?>) getProviderClassMethod.invoke(factoryClass);
            Class<?> delegateClass = Class.forName("android.webkit.WebViewDelegate");
            Constructor<?> delegateConstructor = delegateClass.getDeclaredConstructor();
            delegateConstructor.setAccessible(true);
            if(sdkInt < 26){//低于Android O版本
                Constructor<?> providerConstructor = factoryProviderClass.getConstructor(delegateClass);
                if (providerConstructor != null) {
                    providerConstructor.setAccessible(true);
                    sProviderInstance = providerConstructor.newInstance(delegateConstructor.newInstance());
                }
            } else {
                Field chromiumMethodName = factoryClass.getDeclaredField("CHROMIUM_WEBVIEW_FACTORY_METHOD");
                chromiumMethodName.setAccessible(true);
                String chromiumMethodNameStr = (String)chromiumMethodName.get(null);
                if (chromiumMethodNameStr == null) {
                    chromiumMethodNameStr = "create";
                }
                Method staticFactory = factoryProviderClass.getMethod(chromiumMethodNameStr, delegateClass);
                if (staticFactory!=null){
                    sProviderInstance = staticFactory.invoke(null, delegateConstructor.newInstance());
                }
            }

            if (sProviderInstance != null){
                field.set("sProviderInstance", sProviderInstance);
                Log.i(TAG,"Hook success!");
            } else {
                Log.i(TAG,"Hook failed!");
            }
        } catch (Throwable e) {
            Log.w(TAG,e);
        }
    }

包括兼容android8.0.在Application OnCreate方法中加入上面方法即可。

如何你不清楚如何在build.gradle中配置签名文件。那么我下片写一篇如何配置以及jenkins动态变量配置的文章

本文地址:https://blog.csdn.net/chengzuidongfeng/article/details/107941916

相关标签: Android