android 没有root下实现软件自动更新的一些思路和方法
16lz
2021-01-26
做一个简单的记录:
这边主要是考虑到一些设备没有root的情况下,借助Android提供的辅助功能,开启无障碍服务来处理,借鉴了这位大神的一些步骤:https://blog.csdn.net/guolin_blog/article/details/47803149
1.编写一个服务类(MyAccessibilityService)
package com.example.administrator.medx_media.upapkdata;import android.accessibilityservice.AccessibilityService;import android.util.Log;import android.view.accessibility.AccessibilityEvent;import android.view.accessibility.AccessibilityNodeInfo;import java.util.HashMap;import java.util.Map;/** * 智能安装功能的实现类。 * 原文地址:http://blog.csdn.net/guolin_blog/article/details/47803149 * @author guolin * @since 2015/12/7 */public class MyAccessibilityService extends AccessibilityService { Map handledMap = new HashMap<>(); public MyAccessibilityService() { } @Override public void onAccessibilityEvent(AccessibilityEvent event) { AccessibilityNodeInfo nodeInfo = event.getSource(); if (nodeInfo != null) { int eventType = event.getEventType(); if (eventType== AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED || eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { if (handledMap.get(event.getWindowId()) == null) { boolean handled = iterateNodesAndHandle(nodeInfo); if (handled) { handledMap.put(event.getWindowId(), true); } } } } } private boolean iterateNodesAndHandle(AccessibilityNodeInfo nodeInfo) { if (nodeInfo != null) { int childCount = nodeInfo.getChildCount(); if ("android.widget.Button".equals(nodeInfo.getClassName())) { String nodeContent = nodeInfo.getText().toString(); Log.d("TAG", "content is " + nodeContent); if ("安装".equals(nodeContent) || "完成".equals(nodeContent)) { nodeInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK); return true; } } else if ("android.widget.ScrollView".equals(nodeInfo.getClassName())) { nodeInfo.performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); } for (int i = 0; i < childCount; i++) { AccessibilityNodeInfo childNodeInfo = nodeInfo.getChild(i); if (iterateNodesAndHandle(childNodeInfo)) { return true; } } } return false; } @Override public void onInterrupt() { }}
2.在文件清单,添加该服务:
3.在res目录下,新建xml文件夹,创建文件:
<?xml version="1.0" encoding="utf-8"?>
4.下载好apk,执行安装,弹出安装界面
5.为了解决,监听到安装完成,之后,弹框停留不能取消隐藏的问题,加入一个广播接收者,5秒钟之后,再去重启软件:
/** * 检测软件卸载和安装测试 */public class MyReceiver2 extends BroadcastReceiver { private String rootfilepath; Context mcontext; String packageName; Handler handler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case 1: // Log.i(TAG, "handleMessage: 执行了"); forceStopApp(packageName); Intent LaunchIntent = mcontext.getPackageManager().getLaunchIntentForPackage(packageName); LaunchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//.testDemo.TestFrag_ShowhidedActivity LaunchIntent.setClassName("com.example.administrator.xxx", "com.example.administrator.xxx.xxx"); mcontext.startActivity(LaunchIntent); break; } } }; @Override public void onReceive(Context context, Intent intent) { // TODO: This method is called when the BroadcastReceiver is receiving mcontext = context; PackageManager manager = context.getPackageManager(); if (intent.getAction().equals(Intent.ACTION_PACKAGE_ADDED)) { packageName = intent.getData().getSchemeSpecificPart(); Log.i(TAG, "123456安装成功: " + packageName); } if (intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED)) { packageName = intent.getData().getSchemeSpecificPart(); Log.i(TAG, "123456卸载成功: " + packageName); } if (intent.getAction().equals(Intent.ACTION_PACKAGE_REPLACED)) { packageName = intent.getData().getSchemeSpecificPart(); Log.i(TAG, " 123456替换成功: " + packageName); handler.sendEmptyMessageDelayed(1, 2000); } } // 传入应用的包名即可kill掉应用 private void forceStopApp(String packageName) { ActivityManager am = (ActivityManager) mcontext .getSystemService(Context.ACTIVITY_SERVICE); try { Method method = Class.forName("android.app.ActivityManager").getMethod("forceStopPackage", String.class); method.invoke(am, packageName);// am.forceStopPackage(packageName); } catch (Exception e) { e.printStackTrace(); } } public void deletefile() { //具体文件路径引用 if (isSDCardMounted()) { rootfilepath = Environment.getExternalStorageDirectory().getPath() + UitlData.MEADIA_VIDEO; } else { rootfilepath = Environment.getDataDirectory().getPath() + UitlData.MEADIA_VIDEO; } Log.i(TAG, "deletefile: 删除了文件夹=" + rootfilepath); deleteDir(rootfilepath); } /** * 删除文件夹 * * @param path */ public static void deleteDir(String path) { File dir = new File(path); deleteDirWihtFile(dir); } /** * 删除文件及文件夹 */ public static void deleteDirWihtFile(File dir) { if (dir == null || !dir.exists() || !dir.isDirectory()) return; for (File file : dir.listFiles()) { System.gc(); if (file.isFile()) file.delete(); // 删除所有文件 else if (file.isDirectory()) deleteDirWihtFile(file); // 递规的方式删除文件夹 } dir.delete();// 删除目录本身 }}
6.启动app前,判断是否开启无障碍服务:
int enable = Settings.Secure.getInt(this.getApplication().getContentResolver(), Settings.Secure.ACCESSIBILITY_ENABLED, 0); if (enable == 1) { Log.i(TAG, "onCreate: 无障碍开启"); // 开始安装 } else { Log.i(TAG, "onCreate: 无障碍没开启"); Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS); startActivity(intent); }
,虽然到这一步,基本解决了这个安装完之后,弹框不消失的问题,但实际上它还是没有取消那框,只是检测安装了相同的apk,开个重启的方法,只是隐藏了,实际上退出软件之后,它一样还是存在的,但是不阻挡该app的正常使用。当然没有十全十美的办法,在没有root的Android 系统上,是我们暂时的办法,当然可以去root的情况下,又有谁会去用这个“本方法”,如果你有更好的方法和思路,可以留言一起交流学习。
更多相关文章
- android listview 删除item 刷新 notifyDataSetChanged()失效问
- android studio安装 虚拟机"VT-x is disabled in BIOS"
- android 配置ndk-builder
- 国际版TikTok使用教程(2020更新)
- Android项目结构和HelloWorld
- Ubuntu 16.04 64bit 编译 Android(安卓)4.4 源码
- Android(安卓)Studio和SDK的下载安装以及个性化设置方法
- Android:开发环境搭建、移植
- Android(安卓)Studio 使用过程中的坑