美文网首页
2019-03-19 android 模拟点击Lanucher

2019-03-19 android 模拟点击Lanucher

作者: KK葫芦娃 | 来源:发表于2019-03-19 21:18 被阅读0次

    问题

    最近在做需求,需要从外部APP跳转到本APP的目标面处理完结果后,返回目标的APP。

    要求不能重复打开外部APP的某个activity,必须将外部APP模拟在Launcher点击启动一样。

    分析

    在系统的桌面上,我们点击图标,如果应用没有启动,那么应用会从首页启动,如果应用已经启动过,那么应用就会直接打开,系统是如何做到的呢?

    经查询(一阵百度骚搜索),intent数据为从桌面程序中laucher.db数据库favorite表中intent字段所取得的数据 为

    数据可以简单理解为Intent序列化后的数据。也就是Intent需要设置为以上数据才能达到你希望的效果。

    ACTION为android.intent.action.MAIN,
    category为android.intent.category.LAUNCHER,
    launchFlags为0x10200000,
    component可以简单理解为该应用的启动页activity。
    launchFlags是用来表示应用页的启动属性,
    此处0x10200000表示属性为Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED

    代码

    那这样的话,我们模拟Intent去配置相应的flag就行了呗

    1. 通过包名找到APP启动页
    public static Intent getAppOpenIntentByPackageName(Context context,String packageName){
            // MainActivity完整名
            String mainAct = null;
            // 根据包名寻找MainActivity
            PackageManager pkgMag = context.getPackageManager();
            Intent intent = new Intent(Intent.ACTION_MAIN);
            intent.addCategory(Intent.CATEGORY_LAUNCHER);
            intent.setFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED|Intent.FLAG_ACTIVITY_NEW_TASK);
    
            List<ResolveInfo> list = pkgMag.queryIntentActivities(intent,
                    PackageManager.GET_ACTIVITIES);
            for (int i = 0; i < list.size(); i++) {
                ResolveInfo info = list.get(i);
                if (info.activityInfo.packageName.equals(packageName)) {
                    mainAct = info.activityInfo.name;
                    break;
                }
            }
            if (TextUtils.isEmpty(mainAct)) {
                return null;
            }
            intent.setComponent(new ComponentName(packageName, mainAct));
            return intent;
        }
    

    2.Intent现在已经构造好了,那么就启动吧,但通过搜索,对于启动的Context,还有这样的处理

    public static Context getPackageContext(Context context, String packageName) {
            Context pkgContext = null;
            if (context.getPackageName().equals(packageName)) {
                pkgContext = context;
            } else {
                // 创建第三方应用的上下文环境
                try {
                    pkgContext = context.createPackageContext(packageName,
                            Context.CONTEXT_IGNORE_SECURITY
                                    | Context.CONTEXT_INCLUDE_CODE);
                } catch (NameNotFoundException e) {
                    e.printStackTrace();
                }
            }
            return pkgContext;
        }
    
    

    为什么要判断context是否为被启动的acticity的包名呢?我在这里很迷惑

    但让我更迷惑的地方在于context.createPackageContext
    注释里面说主要作用是:创建其它程序的Context,通过创建的这个Context,就可以访问该软件包的资源,甚至可以执行其它软件包的代码
    但是有限制条件,除非他们拥有想用的用户ID和签名,用户ID是什么?待解决
    最后,启动代码

    public static boolean openPackage(Context context, String packageName) {
            Context pkgContext = getPackageContext(context, packageName);
            Intent intent = getAppOpenIntentByPackageName(context, packageName);
            if (pkgContext != null && intent != null) {
                pkgContext.startActivity(intent);
                return true;
            }
            return false;
        }
    

    总结和问题

    笔者在测试的时候遇到过兼容性问题,经过查询加入了** Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT)**
    查询原因可查看应用launchMode

    https://www.zhihu.com/question/30153342/answer/47080956
    https://blog.csdn.net/wangguidong520/article/details/53331186
    https://blog.csdn.net/wangbole/article/details/22876179
    https://www.cnblogs.com/JianXu/p/5376642.html
    https://www.jianshu.com/p/62ee47a659f1

    相关文章

      网友评论

          本文标题:2019-03-19 android 模拟点击Lanucher

          本文链接:https://www.haomeiwen.com/subject/zdhgmqtx.html