要实现静默升级,首先要准备的
一般需要该应用是系统级别的应用,经过了平台下发的对应签名apk。
即:
1.内置到ROM,即APK包的安装位置是/system/app下。(制成一个系统刷机包)
2.使用APK的目标安装系统同样的签名。(系统签名)
当然不同平台的签名是不一样的,这个需要根据平台业务来具体确认,第三方Rom这样做也是处于保护系统安全的角度来考虑的。
一般静默升级的代码写法,包含两类
一类是该系统是开放了Root权限
二类是系统没有开放Root权限
开放了root权限的系统,支持静默升级的方式比较多
具有Root权限的静默升级,是用mp install -r 这样的方式实现的,类似adb推送的命令进行的安装
开放了Root权限的
开放了Root权限的静默升级就比较简单,但这个代码稍微要改一改,比较容易卡死
//静默安装
protected void excutesucmd(String currenttempfilepath) {
Process process = null;
OutputStream out = null;
InputStream in = null;
try {
// 请求root
process = Runtime.getRuntime().exec("sh");
out = process.getOutputStream();
// 调用安装
out.write(("pm install -r " + currenttempfilepath + "\n").getBytes());
in = process.getInputStream();
int len = 0;
byte[] bs = new byte[256];
while (-1 != (len = in.read(bs))) {
String state = new String(bs, 0, len);
if (state.equals("success\n")) {
//静态注册自启动广播
Intent intent = new Intent();
//与清单文件的receiver的anction对应
intent.setAction("android.intent.action.PACKAGE_REPLACED");
// 发送广播
sendBroadcast(intent);
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.flush();
out.close();
}
if (in != null) {
in.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
没有开放Root权限的
根据安卓系统的6.0为界进行版本区分,可以用如下的几个写法
比如安卓系统6.0以上的机型静默安装可以这么写
public static boolean installPackage(Context context, InputStream in, String packageName) throws IOException {
PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL);
params.setAppPackageName(packageName);
// set params
int sessionId = packageInstaller.createSession(params);
PackageInstaller.Session session = packageInstaller.openSession(sessionId);
OutputStream out = session.openWrite(packageName, 0, -1);
byte[] buffer = new byte[65536];
int c;
while ((c = in.read(buffer)) != -1) {
out.write(buffer, 0, c);
}
session.fsync(out);
in.close();
out.close();
session.commit(createIntentSender(context, sessionId));
return true;
}
private static IntentSender createIntentSender(Context context, int sessionId) {
PendingIntent pendingIntent = PendingIntent.getBroadcast(context,sessionId,new Intent(Intent.ACTION_PACKAGE_ADDED),PendingIntent.FLAG_UPDATE_CURRENT);
return pendingIntent.getIntentSender();
}
静默卸载这么写
String appPackage = "net.owlsmart.tv";
Intent intent = new Intent(getActivity(), getActivity().getClass());
PendingIntent sender = PendingIntent.getActivity(getActivity(), 0, intent, 0);
PackageInstaller mPackageInstaller = getActivity().getPackageManager().getPackageInstaller();
mPackageInstaller.uninstall(appPackage, sender.getIntentSender());
参数的转化与补充知识
String --> InputStream
ByteArrayInputStream stream = new ByteArrayInputStream(str.getBytes());
InputStream --> String
String inputStream2String(InputStream is){
BufferedReader in = new BufferedReader(new InputStreamReader(is));
StringBuffer buffer = new StringBuffer();
String line = "";
while ((line = in.readLine()) != null){
buffer.append(line);
}
return buffer.toString();
}
File --> InputStream
InputStream in = new FileInputStream(file);
InputStream --> File
public void inputstreamtofile(InputStream ins,File file){
OutputStream os = new FileOutputStream(file);
int bytesRead = 0;
byte[] buffer = new byte[8192];
while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
os.write(buffer, 0, bytesRead);
}
os.close();
ins.close();
}
安卓6.0及以下的这么写
低版本Android 6.0以下,大部分app的静默安装都是通过 移植系统源码中的相关AIDL 文件,进行调用pm里面的android方法:
普通情况下肯定是调用不到的。在源码\frameworks\base\core\java\android\content\pm目录下PackageManager.java,应该发现在注释行里有加上@hide声明。调用的安装下载接口如下:
public abstract void installPackage(Uri packageURI,IPackageInstallObserver observer, int flags,String installerPackageName);
public abstract void deletePackage(String packageName,IPackageDeleteObserver observer, int flags);最简单的就是直接拷贝4个文件即可:
PackageManager.java
IPackageDeleteObserver.aidl
IPackagerInstallObserver.aidl
IPackageMoveObserver.aidl
然后把PackageManager.java中报的异常的接口都注释掉即可,然后直接调用pm里面的方法。
/*** 静默安装* */
public static void autoInstallApk(Context context, String fileName,String packageName, String APPName) {
Log.d(TAG, “jing mo an zhuang:” + packageName + “,fileName:” + fileName);File file = new File(fileName);
int installFlags = 0;
if (!file.exists())
return;
installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
if (hasSdcard()) {
installFlags |= PackageManager.INSTALL_EXTERNAL;
}
PackageManager pm = context.getPackageManager();
try {
IPackageInstallObserver observer = new MyPakcageInstallObserver(context, APPName, appId, fileName,packageName,type_name);
Log.i(TAG, “########installFlags:” + installFlags+”packagename:”+packageName);
pm.installPackage(Uri.fromFile(file), observer, installFlags,packageName);
} catch (Exception e) {
}
}
静默安装实现的接口,这样写
class MyPakcageInstallObserver extends IPackageInstallObserver.Stub {
Context cxt;
String appName;
String filename;
String pkname;
public MyPakcageInstallObserver(Context c, String appName, String filename, String packagename) {
this.cxt = c;
this.appName = appName;
this.filename = filename;
this.pkname = packagename;
}
@Override
public void packageInstalled(String packageName, int returnCode) {
Log.i(TAG, “returnCode = ” + returnCode);// 返回1代表安装成功
if (returnCode == 1) {
//TODO
}
Intent it = new Intent();
it.setAction(CustomAction.INSTALL_ACTION);
it.putExtra(“install_returnCode”, returnCode);
it.putExtra(“install_packageName”, packageName);
it.putExtra(“install_appName”, appName); cxt.sendBroadcast(it);
}
}
apk卸载
@Override
public void deletePackage(String packageName, IPackageDeleteObserver observer, int flags) {
try {
mPM.deletePackageAsUser(packageName, observer, UserHandle.myUserId(), flags);
} catch (RemoteException e) {
// Should never happen!
}
}