安卓静默安装与自启动
写在前面
静默安装如果在正常的用户手机上除非是残疾用户使用,不然都是耍流氓
本次是因为做一个硬件功能,不带操作的硬件在版本更新的时候只能使用静默安装
不想听瞎逼逼可以直接看总结
说一下大概流程
静默安装需要操作的应用包括需要安装的app(最后安装的app)和被静默安装的app(要被替换掉的)
首先是最后要安装的app需要的操作
-
写app(废话)
-
设置安装监听权限
-
做安装与卸载的广播监听
-
接收到广播就调用打开应用方法
-
打包应用
-
搞定
代码撸起来
1 首先写个app(省略一万行代码)
2 添加监听安装和卸载权限
<uses-permission android:name="android.permission.DELETE_PACKAGES" />
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
3 做安装与卸载的广播监听,接收到广播就调用打开应用方法
自定义一个receiver继承BroadcastReceiver
public class BootReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//接收安装广播
if (intent.getAction().equals("android.intent.action.PACKAGE_ADDED")) {
String packageName = intent.getDataString();
// TODO: ActivityHome为启动页
Intent intent2 = new Intent(context, ActivityHome.class);
intent2.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent2);
Log.e("onReceive", "安装了:" + packageName + "包名的程序");
}
//接收重新安装广播
if (intent.getAction().equals("android.intent.action.PACKAGE_REPLACED")) {
Toast.makeText(context, "升级了一个安装包,重新启动此程序", Toast.LENGTH_SHORT).show();
// TODO: ActivityHome为启动页
Intent intent2 = new Intent(context, ActivityHome.class);
intent2.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent2);
}
//接收卸载广播
if (intent.getAction().equals("android.intent.action.PACKAGE_REMOVED")) {
String packageName = intent.getDataString();
System.out.println("卸载了:" + packageName + "包名的程序");
}
}
}
4 打包应用@@%$&%*&%&%&^%
之后就可以将此app放到服务器上面等待下载安装了
以上,此app就具有被唤醒的功能,也就是我们静默安装的目标app 可以 被唤醒了
然后是最后具备静默安装的App需要的操作
-
添加安装app权限和超级用户权限
-
静默安装逻辑
-
打包
-
系统签名
-
搞定
代码接着撸起来
1 添加安装app权限和超级用户权限
//有root的设备声明超级用户权限
<uses-permission android:name="android.permission.ACCESS_SUPERUSER" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
添加了这个权限还是啊会提示错误,能编译通过就不要管他
2 静默安装需要反射系统的方法来实现
public void installPackage(String apkFile) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException, ClassNotFoundException, NoSuchMethodException {
Class<?> pmClz = pm.getClass();
if (Build.VERSION.SDK_INT >= 21) {
Class<?> aClass = Class.forName("android.app.PackageInstallObserver");
Constructor<?> constructor = 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(pm, Uri.fromFile(new File(apkFile)),
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(pm, Uri.fromFile(new File(apkFile)), null, 2,
null);
}
}
3 在下载安装包完成后调用安装逻辑
4 做应用系统签名 <---重点
普通签名的应用在调用静默安装的时候会抛没有此方法的异常,需要对它进行系统应用签名才能做到
所以
|
|
首先 将我们的app打包
然后使用签名工具---链接---
下载此工具包 将apk安装包放到工具包目录下,使用命令工具
java -jar signapk.jar platform.x509.pem platform.pk8 unsign.apk signed.apk
签名完成的安装包就是具备静默安装功能的安装包了,将此安装包安装到设备上,就可以测试静默安装了
总结
静默安装的app当然是需要每次升级安装的版本具备静默安装下一个应用的功能,所以一般来说,一个要做静默安装的应用必须具备静默安装其他app和被其他app静默安装的时候可以唤醒,所以以上的两个功能在同一个apk里面都必须具备
所以总结下步骤(其实看这个就可以了)
- 设置下载和监听安装、重新安装、卸载的权限
<uses-permission android:name="android.permission.DELETE_PACKAGES" />
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
//有root的设备声明超级用户权限
<uses-permission android:name="android.permission.ACCESS_SUPERUSER" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- 自定义receiver 继承BroadcastReceiver 在收到安装或重新安装的action时打开app操作
public class BootReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//接收安装广播
if (intent.getAction().equals("android.intent.action.PACKAGE_ADDED")) {
String packageName = intent.getDataString();
// TODO: ActivityHome为启动页
Intent intent2 = new Intent(context, ActivityHome.class);
intent2.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent2);
Log.e("onReceive", "安装了:" + packageName + "包名的程序");
}
//接收重新安装广播
if (intent.getAction().equals("android.intent.action.PACKAGE_REPLACED")) {
Toast.makeText(context, "升级了一个安装包,重新启动此程序", Toast.LENGTH_SHORT).show();
// TODO: ActivityHome为启动页
Intent intent2 = new Intent(context, ActivityHome.class);
intent2.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent2);
}
//接收卸载广播
if (intent.getAction().equals("android.intent.action.PACKAGE_REMOVED")) {
String packageName = intent.getDataString();
System.out.println("卸载了:" + packageName + "包名的程序");
}
}
}
- 在清单文件注册以上receiver
<receiver
android:name=".silenceInstall.BootReceiver"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_ADDED" />
<action android:name="android.intent.action.PACKAGE_REPLACED" />
<action android:name="android.intent.action.PACKAGE_REMOVED" />
<data android:scheme="package" />
</intent-filter>
- 做静默安装逻辑,在安装包下载完成后调用安装方法
public void installPackage(String apkFile) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException, ClassNotFoundException, NoSuchMethodException {
Class<?> pmClz = pm.getClass();
if (Build.VERSION.SDK_INT >= 21) {
Class<?> aClass = Class.forName("android.app.PackageInstallObserver");
Constructor<?> constructor = 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(pm, Uri.fromFile(new File(apkFile)),
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(pm, Uri.fromFile(new File(apkFile)), null, 2,
null);
}
}
- 打包app
$%#$^$&^%*^*^&
- 做系统签名
系统签名可以参考
系统签名实践
使用系统签名工具---》
使用命令
java -jar signapk.jar platform.x509.pem platform.pk8 unsign.apk signed.apk
- 搞定