Android8.1 以上静默安装实现

雨燕双飞 提交于 2020-02-28 09:46:31

前提是你已经拥有了当前 android 设备的系统签名,比如定制设备开发

一、获取系统签名 jks 文件

在 android 源码目录下路径 build/target/product/security/ 下,存在 platform.pk8、platform.x509.pem

这两货就是我们平常说的系统签名,有了系统签名再给app增加 android.uid.system 属性,app就变成了系统级app。

当我们在 AndroidManifest.xml 中增加了 uid 属性,AS 就无法直接运行安装调试了,会出现如下错误

The application could not be installed: INSTALL_FAILED_SHARED_USER_INCOMPATIBLE
Installation failed due to: ‘no signatures that match those in shared user android.uid.system;’

我们一般都需要先打包app,然后在用 signapk.jar 给app签名后再安装运行,这样调试起来就很繁琐。那么我们就来生成一个

platform.jks,直接在AS中就能Run起来。

在 build/target/product/security/ 路径下,执行下面三条指令


	openssl pkcs8 -inform DER -nocrypt -in platform.pk8 -out platform.pem

	openssl pkcs12 -export -in platform.x509.pem -out platform.p12 -inkey platform.pem -password pass:123 -name test

	keytool -importkeystore -deststorepass 123 -destkeystore platform.jks -srckeystore platform.p12 -srcstoretype PKCS12 -srcstorepass 123

这样就会生成 platform.jks,这就是我们要的,还多出来 platform.p12、platform.pem 忽略就好

platform.jks 对应的 keyAlias 为上面的name,test,password 为 123,所以在 AS 的 build.gradle 配置如下

 signingConfigs {
        releaseConfig {
            storeFile file("platform.jks")
            storePassword '123'
            keyPassword '123'
            keyAlias = 'test'
        }
        debug {
            storeFile file("platform.jks")
            storePassword '123'
            keyPassword '123'
            keyAlias = 'test'
        }
    }

二、增加 android.uid.system 属性,反射调用 installPackage()

导入 android_dependency.jar

private void SilentInstallApkByReflect(String apkPath) {
         apkPath = Environment.getExternalStorageDirectory()+"/Android/11.apk";
        try {
            PackageManager packageManager = getPackageManager();
            Method method = packageManager.getClass().getDeclaredMethod("installPackage",
                    new Class[] {Uri.class, IPackageInstallObserver.class, int.class, String.class} );
            method.setAccessible(true);
            File apkFile = new File(apkPath);
            Uri apkUri = Uri.fromFile(apkFile);

            method.invoke(packageManager, new Object[]{apkUri, new IPackageInstallObserver.Stub() {
                @Override
                public void packageInstalled(String pkgName, int resultCode) throws RemoteException {
                    Log.d("install", "packageInstalled = " + pkgName + "; resultCode = " + resultCode);
                }
            }, Integer.valueOf(2), ""});
        }catch (Exception e) {
            e.printStackTrace();
        }
}

不加 android.uid.system 属性会报如下错误

W/System.err: Caused by: java.lang.SecurityException: Neither user 10078 nor current process has android.permission.INSTALL_PACKAGES.
W/System.err:     at android.os.Parcel.readException(Parcel.java:2005)
W/System.err:     at android.os.Parcel.readException(Parcel.java:1951)
W/System.err:     at android.content.pm.IPackageManager$Stub$Proxy.installPackageAsUser(IPackageManager.java:4092)
W/System.err:     at android.app.ApplicationPackageManager.installCommon(ApplicationPackageManager.java:1705)
W/System.err:     at android.app.ApplicationPackageManager.installPackage(ApplicationPackageManager.java:1686)
W/System.err: 	... 14 more

安装成功将回调 packageInstalled()
D/install: packageInstalled = com.sound.smartphone; resultCode = 1

同时通过监听静态广播 android.intent.action.PACKAGE_REPLACED 判断是否安装成功

<receiver android:name=".ServiceBroadcastReceiver">
	<intent-filter android:priority="1000">
		<action android:name="android.intent.action.PACKAGE_REPLACED" />
		<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
		<data android:scheme="package" />
	</intent-filter>
</receiver>

if ("android.intent.action.PACKAGE_REPLACED".equals(action)
                || "android.intent.action.MY_PACKAGE_REPLACED".equals(action)){
	try{
		String scheme = intent.getScheme();
		String packageName = intent.getData().getSchemeSpecificPart();
		if(context.getPackageName().equals(packageName)) {
			Toast.makeText(context, "成功升级新版本!", Toast.LENGTH_SHORT).show();
		}
		LogUtils.i("KePackageService", "收到 ACTION_PACKAGE_REPLACED");
		LogUtils.e("KePackageService", " scheme="+scheme);
		LogUtils.e("KePackageService", " schemeSpecificPart="+packageName);
	}catch (Exception e){
		e.printStackTrace();
	}
}

E/LogUtils: action=android.intent.action.MY_PACKAGE_REPLACED
I/KePackageService: 收到 ACTION_PACKAGE_REPLACED
E/KePackageService: scheme=package
E/KePackageService: schemeSpecificPart=com.sound.smartphone

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!