Android启动一个只知道包名的APP

网上能找到很多关于本文主题的代码——Android启动一个只知道包名的APP,那我为什么还要在此啰嗦一下呢?
你可能参考网上各种方式都打不开APP,还不是很清楚原因,那么我这里就只是做一个提醒吧,害怕你忘了或者没注意到过。

我们知道,在TV上开发的APP和在移动端的有一些差别。

  • 一个应用运行在TV设备中,必须在它的manifest中定义一个启动activity,用intent filter包含CATEGORY_LEANBACK_LAUNCHER。
  • 这个filter表明你的应用是在TV上可用,并且为Google Play上发布TV应用所必须。
  • 定义这个intent也意味着点击主屏幕的应用图标时,就是打开的这个activity。

所以,你要启动一个只知道包名的APP,在TV上和移动端还是有些差别的,敲重点了。
1、我们先抛弃如下方式:

Intent intent = context.getPackageManager().getLaunchIntentForPackage(packageName);
context.startActivity(intent);

因为它可能会返回为空,高版本Android使用它会有缺陷的。
2、我们常用方式,即移动端的正确解锁方式:

PackageManager packageManager = context.getPackageManager();
        Intent resolveIntent = new Intent(Intent.ACTION_MAIN, null);
        resolveIntent.addCategory(Intent.CATEGORY_LAUNCHER);
        resolveIntent.setPackage(packageName);

        List<ResolveInfo> apps = packageManager.queryIntentActivities(
                resolveIntent, 0);

        ResolveInfo ri = apps.iterator().next();
        if (ri != null) {
            String className = ri.activityInfo.name;

            Intent intent = new Intent(Intent.ACTION_MAIN);
            intent.addCategory(Intent.CATEGORY_LAUNCHER);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            ComponentName cn = new ComponentName(packageName, className);

            intent.setComponent(cn);
            context.startActivity(intent);
        }

3、TV端方式需要做个兼容(这也是很多同学打不开APP的原因)重点中的重点:

{
		String activityName = getActivityNameFromPackage(context, packageName);
        if (activityName == null) {
            return;
        }
        Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        ComponentName cn = new ComponentName(packageName, activityName);
        intent.setComponent(cn);
        context.startActivity(intent);
}


private static String getActivityNameFromPackage(Context context, String packageName) {
        try {
            PackageManager pm = context.getPackageManager();
            PackageInfo pi = pm.getPackageInfo(packageName, 0);
            Intent resolveIntent = new Intent(Intent.ACTION_MAIN, null);
            resolveIntent.setPackage(pi.packageName);
            resolveIntent.addCategory(Intent.CATEGORY_LEANBACK_LAUNCHER);
            List<ResolveInfo> apps = pm.queryIntentActivities(resolveIntent, 0);
            if (apps != null) {
                Log.d(TAG, "getActivityNameFromPackage: LEANBACK_LAUNCHER: launcherIntent size == " + apps.size());
            }
            if (apps == null || apps.isEmpty()) {
                resolveIntent.removeCategory(Intent.CATEGORY_LEANBACK_LAUNCHER);
                resolveIntent.addCategory(Intent.CATEGORY_LAUNCHER);
                apps = pm.queryIntentActivities(resolveIntent, 0);
                Log.d(TAG, "getActivityNameFromPackage: LAUNCHER: launcherIntent size == " + apps.size());
            }
            if (apps != null && apps.size() > 0) {
                ResolveInfo info = apps.iterator().next();
                if (info != null) {
                    return info.activityInfo.name;
                }
            } else {
                Log.d(TAG, "getActivityNameFromPackage: apps is null");
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

最后,我们知道,对CATEGORY_LEANBACK_LAUNCHER 和 CATEGORY_LAUNCHER的正确理解是解决此问题的根本之道。

你可能感兴趣的:(Android)