Android静默升级的菜鸟教程

您所在的位置:网站首页 app并安装 Android静默升级的菜鸟教程

Android静默升级的菜鸟教程

#Android静默升级的菜鸟教程| 来源: 网络整理| 查看: 265

前言

20220617更新,补上未root升级方式,需要android.uid.system+系统签名,Android 10.0,见文末。 目前已知的实现方式:

获取su,通过pm命令实现静默安装通过辅助功能实现静默安装(有弹窗,只是不需要手动点击安装)root,覆盖安装,将应用下载到system下后重启系统通过pm install实现静默安装,需要系统签名 需要知道

1.不是root过的手机就一定能通过Runtime.getRuntime().exec(“su”);代码获取root权限。虽然通过su或adb root可以切换到root,但是在代码中不同,在源码中有如下判断。

if (myuid != AID_ROOT && myuid != AID_SHELL) { fprintf(stderr,"su: uid %d not allowed to su\n", myuid); return 1; }

2.不是非要获取su才能执行pm install来实现静默升级。这也是我没有通过1来实现静态升级的原因。下面介绍的我就是通过这种方式实现的静默升级。

3.应用放到system/app,需要root

4.如果应用声明为系统应用,那么需要系统签名,否则签名无法通过,开机时会报签名错误,无法识别安装

5.即时不声明为系统应用,不需要系统签名,依然可以放到system/app下

实现静默升级,Android7.1

前提:

系统签名,即使su你无法拿到也不影响。

应用必须使用系统签名,因为咱要用系统权限

android:sharedUserId="android.uid.system"

如何系统签名,不在本文范围内。

代码如下:

/** * 静默安装 * * @param path */ private void installPackage(String path) { String packageName = MyApplication.get().getApplicationContext().getPackageName(); try { new ProcessBuilder() .command("pm", "install", "-i", packageName, path) .start(); } catch (IOException e) { e.printStackTrace(); } }

path替换为你自己Apk的路径,包名也记得替换,这个坑我开始折磨了一段时间,我开始用的-r,没有包名,导致一直空指针异常。。。。。

pm install -i 包名 apk路径 Android10.0 PackageInstaller静默升级,

机器未root,不过有系统签名,还是和上面一样,因为要使用系统INSTALL_PACKAGES权限,测试10.0升级成功。下面是代码

public class PackageManagerCompatP { private static final String TAG = PackageManagerCompatP.class.getSimpleName(); @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public static void install(Context context, String apkFilePath, PackageManager packageManager) { File apkFile = new File(apkFilePath); PackageInstaller packageInstaller = packageManager.getPackageInstaller(); PackageInstaller.SessionParams sessionParams = new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL); sessionParams.setSize(apkFile.length()); int sessionId = createSession(packageInstaller, sessionParams); if (sessionId != -1) { boolean copySuccess = copyInstallFile(packageInstaller, sessionId, apkFilePath); MainLog.d(TAG,"install: " + copySuccess); if (copySuccess) { execInstallCommand(context, packageInstaller, sessionId); } } } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) private static int createSession(PackageInstaller packageInstaller, PackageInstaller.SessionParams sessionParams) { int sessionId = -1; try { sessionId = packageInstaller.createSession(sessionParams); } catch (IOException e) { e.printStackTrace(); } return sessionId; } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) private static boolean copyInstallFile(PackageInstaller packageInstaller, int sessionId, String apkFilePath) { InputStream in = null; OutputStream out = null; PackageInstaller.Session session = null; boolean success = false; try { File apkFile = new File(apkFilePath); session = packageInstaller.openSession(sessionId); out = session.openWrite("base.apk", 0, apkFile.length()); in = new FileInputStream(apkFile); int total = 0, c; byte[] buffer = new byte[65536]; while ((c = in.read(buffer)) != -1) { total += c; out.write(buffer, 0, c); } session.fsync(out); success = true; } catch (IOException e) { e.printStackTrace(); } finally { closeQuietly(out); closeQuietly(in); closeQuietly(session); } return success; } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) private static void execInstallCommand(Context context, PackageInstaller packageInstaller, int sessionId) { PackageInstaller.Session session = null; try { session = packageInstaller.openSession(sessionId); Intent intent = new Intent(context, InstallReceiver.class); PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT); session.commit(pendingIntent.getIntentSender()); MainLog.d(TAG,"execInstallCommand: "); } catch (IOException e) { e.printStackTrace(); } finally { closeQuietly(session); } } private static void closeQuietly(Closeable c) { if (c != null) { try { c.close(); } catch (IOException ignored) { ignored.printStackTrace(); } } } }

这是广播,可以监听应用已安装

String appPackageName = context.getPackageName(); if (intent.getAction().equals(Intent.ACTION_PACKAGE_REPLACED)) { String packageName = intent.getData().getEncodedSchemeSpecificPart(); if (packageName.equals(appPackageName)) { // 重新启动APP Intent intentToStart = context.getPackageManager().getLaunchIntentForPackage(packageName); context.startActivity(intentToStart); } }

参考

脱坑

脱坑

脱坑



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3