原理:在app添加一个智能辅助服务然后在设置界面打开智能辅助即可在服务中监听屏幕各种状态,我们可以监听安装的install包然后监听安装弹框的“安装”点击按钮,监听到直接进入安装流程就可以了
如果需要自动开启辅助功能可以参考:Android 应用自动开启辅助(无障碍)功能并使用辅助(无障碍)功能_android 自动开启无障碍服务_龚礼鹏的博客-CSDN博客
可能上面说的比较绕,下面直接来流程:
1.manifes中的配置如下:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.midea.cabinet">
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/><!-- 8.0系统安装apk权限 -->
<!-- 下载后安装apk。注:7.0及以上系统禁止直接访问storage私有文件,需通过FileProvider生成content://URI去授予临时访问的权限,实现应用间数据共享 -->
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
<!--
android:label(可选) 在辅助功能(无障碍)的系统设置会使用该名称,若不设置,则会使用<application android:label
android:process(可选) 把该服务设在单独进程中,进程名以[冒号:]开头,是本应用的私有进程,其它应用无法访问
android:permission(必需) 添加权限以确保只有系统可以绑定到该服务
-->
<service
android:name=".updateApk.AutoInstallService"
android:label="自动安装"
android:process=":install"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
<!--在xml文件配置辅助功能,也可在onServiceConnected()中使用setServiceInfo()动态配置-->
<meta-data
android:name="android.accessibilityservice"
android:resource="@xml/accessibility_config" />
</service>
</application>
</manifest>
2.res中新建xml文件夹然后添加两个文件分别是accessibility_config.xml和file_paths.xml,内容如下所示:
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeAllMask"
android:accessibilityFeedbackType="feedbackGeneric"
android:accessibilityFlags="flagDefault"
android:canRetrieveWindowContent="true"
android:description="@string/install_smart"
android:packageNames="com.android.packageinstaller"
android:notificationTimeout="100"/>
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<!-- apk存放路径:getExternalCacheDir()/apk/xiaomaigui.apk -->
<external-cache-path name="externalcache" path="apk" />
<cache-path name="cache" path="apk"/>
<!--Environment.getExternalStorageDirectory()/xiaomaigui/-->
<external-path
name="externalpath"
path="midea/ApkUpgrade"/>
<root-path name="root" path="system"/>
</paths>
3.添加辅助服务AutoInstallService:
package com.midea.cabinet.updateApk;
import android.accessibilityservice.AccessibilityService;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import com.blankj.utilcode.util.LogUtils;
import java.util.HashMap;
import java.util.Map;
public class AutoInstallService extends AccessibilityService {
private Map<Integer, Boolean> handleMap = new HashMap<>();
@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 (handleMap.get(event.getWindowId()) == null) {
boolean handled = iterateNodesAndHandle(nodeInfo);
if (handled) {
handleMap.put(event.getWindowId(), true);
}
}
}
}
}
@Override
public void onInterrupt() {
}
// 遍历节点,模拟点击安装按钮
private boolean iterateNodesAndHandle(AccessibilityNodeInfo nodeInfo) {
if (nodeInfo != null) {
int childCount = nodeInfo.getChildCount();
if ("android.widget.Button".equals(nodeInfo.getClassName())) {
String nodeCotent = nodeInfo.getText().toString();
LogUtils.d("content is: " + nodeCotent);
LogUtils.e("nodeInfo"+nodeInfo.getClassName());
if ("安装".equals(nodeCotent) || "打开".equals(nodeCotent)) {
nodeInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK);
return true;
}
}
// 遇到 ScrollView 的时候模拟滑动一下
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;
}
}
4.编写安装代码:
/**
* apk安装
*/
private fun installApp(apkPath: String) {
val file = File(apkPath)
val intent = Intent()
intent.action = Intent.ACTION_VIEW
val data = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".fileprovider", file)
} else {
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
Uri.fromFile(file)
}
intent.setDataAndType(data, "application/vnd.android.package-archive")
startActivity(intent)
}
以上 即可完成辅助功能免root安装 需要用户在设置界面的无障碍辅助中打开自己的服务,我上面写的就是需要打开自动安装。