android 没有root下实现软件自动更新的一些思路和方法

 做一个简单的记录:

这边主要是考虑到一些设备没有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<Integer, Boolean> 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.在文件清单,添加该服务:

  <service
            android:name=".upapkdata.MyAccessibilityService"
            android:label="智能安装"
            android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
            <intent-filter>
                <action android:name="android.accessibilityservice.AccessibilityService" />
            </intent-filter>

            <meta-data
                android:name="android.accessibilityservice"
                android:resource="@xml/accessibility_service_config" />
        </service>

3.在res目录下,新建xml文件夹,创建文件:

<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:packageNames="com.android.packageinstaller"
    android:description="智能安装服务,无需用户的任何操作就可以自动安装程序。"
    android:accessibilityEventTypes="typeAllMask"
    android:accessibilityFlags="flagDefault"
    android:accessibilityFeedbackType="feedbackGeneric"
    android:canRetrieveWindowContent="true"
    />

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的情况下,又有谁会去用这个“本方法”,如果你有更好的方法和思路,可以留言一起交流学习。

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值