Android APP的静默安装和自启动
最近碰到项目中碰到一个需求,就是定制开发系统的APP需要静默安装和自启动,于是找了网上很多文章,大致都没怎么能解决,我来说说总结下。
1、Android未root的设备怎么实现静默安装?
这个方法调用静默安装需要apk有系统签名的权限,否则不可以。
需要的权限:
<uses-permission android:name= "android.permission.RESTART_PACKAGES" />
<uses-permission android:name="android.permission.INSTALL_PACKAGES" tools:ignore="ProtectedPermissions" />
代码:
public boolean slienceInstallWithSysSign(String filePath) {
File file =new File(filePath);
PackageManager packageManager =HclyApplication.getInstance().getPackageManager();
ClasspmClz =packageManager.getClass();
try {
if (Build.VERSION.SDK_INT >=21) {
ClassaClass =Class.forName("android.app.PackageInstallObserver");
Constructorconstructor =aClass.getDeclaredConstructor();
constructor.setAccessible(true);
Object installObserver =constructor.newInstance();
Method method =pmClz.getDeclaredMethod("installPackage",Uri.class,aClass,int.class,String.class);
method.setAccessible(true);
method.invoke(packageManager,Uri.fromFile(file),installObserver,2,null);
}else {
Method method =pmClz.getDeclaredMethod("installPackage",
Uri.class,Class.forName("android.content.pm.IPackageInstallObserver"),int.class,String.class);
method.setAccessible(true);
method.invoke(packageManager,Uri.fromFile(file),null,2,null);
}
return true;
}catch (Exception e) {
e.printStackTrace();
}
return false;
}
2、root过的设备怎么静默安装?
其实就是调用pm install -r来安装的,-r是保留原来APP的数据。
代码:
public static boolean slienceInstall(String apkUrl) {
boolean result =false;
DataOutputStream dataOutputStream =null;
BufferedReader errorStream =null;
try {
Process process =Runtime.getRuntime().exec("su");
dataOutputStream =new DataOutputStream(process.getOutputStream());
String command ="pm install -r " + apkUrl +"\n";
dataOutputStream.write(command.getBytes(Charset.forName("utf-8")));
dataOutputStream.flush();
dataOutputStream.writeBytes("exit\n");
dataOutputStream.flush();
process.waitFor();
errorStream =new BufferedReader(new InputStreamReader(process.getErrorStream()));
String msg ="";
String line;
while ((line = errorStream.readLine()) !=null) {
msg += line;
}
if (!msg.contains("Failure")) {
result =true;
}
}catch (Exception e) {
}finally {
try {
if (dataOutputStream !=null) {
dataOutputStream.close();
}
if (errorStream !=null) {
errorStream.close();
}
}catch (IOException e) {
}
}
return result;
}
3、下面我们来说怎么自启动?
自启动这个是最难的,也是我在网上找了很多资料都没有实现的。网上说的自启动就是几种方法:
第一种:sleep 1; am start -n 包名 / 包名+activity名,睡眠一秒开启
这种我亲测过,之前是在5.1的系统可用,但是在8.1的系统就失效了,具体原因也没有去探究
至于:自启动 https://www.jianshu.com/p/782760197969,这个文章中所说的command1 && command2 && command3说是可以的,但是我测试过后发现也不行。
第二种:就是利用广播。
注册广播接收app安装成功的广播,但是经过我测试发现,完全行不通,因为执行pm install的时候原来的apk都被kill掉了,导致无法执行你的广播代码。
我是怎么做的呢?
首先我也是利用第二种广播的方法做的,但是不能写在你自己的APP里面,相当于我要多做一个APP,把广播的代码放在我这个APP中,去监听,然后去启动静默升级的APP,相当于守护进程。至于这个APP什么时候被启动就要看你们自己的需求了,我是放在了有版本更新的地方了!
亲测可以
val intentFilter = IntentFilter()
intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED)
intentFilter.addDataScheme("package")
registerReceiver(mInstallAppBroadcastReceiver,intentFilter)
private val mInstallAppBroadcastReceiver =object : BroadcastReceiver() {
override fun onReceive(context:Context?, intent:Intent?) {
val packageName = intent?.data?.schemeSpecificPart
val action = intent?.action
if (action ==Intent.ACTION_PACKAGE_REPLACED) {
if (packageName ==pkgName) { // 这里的pkgName是我静默升级的那个APP包名,startEntrance是静默升级的APP入口类,全路径的
val componentName = ComponentName(pkgName,startEntrance)
val intent = Intent()
intent.component =componentName
intent.flags =Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(intent)
}
}
}
}
最后记得:unregisterReceiver(mInstallAppBroadcastReceiver)
作者:Smart0928
原文链接:https://www.jianshu.com/p/9f0deecf6e72