前提是你已经拥有了当前 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()
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
来源:CSDN
作者:cczhengv
链接:https://blog.csdn.net/u012932409/article/details/104540171