助力软件开发企业降本增效 PHP / java源码系统,只需一次付费,代码终身使用! 广告
[TOC] # 使用Intent打开第三方应用的方式 ## 通过包名打开 **必要条件** 需要第三方应用配置有默认的入口Activity。 **打开方式** ```java Intent intent = context.getPackageManager().getLaunchIntentForPackage("com.mmbox.xbrowser.pro"); startActivity(intent); ``` 当目标应用不存在或没有默认的入口Activity时,会报如下错误: ```plain Attempt to invoke virtual method 'java.lang.String android.content.Intent.toString()' on a null object reference ``` 因此启动三方应用前应进行非空判断: ```java Intent intent = context.getPackageManager().getLaunchIntentForPackage("com.mmbox.xbrowser.pro"); if (intent == null) { Toast.makeText(context, "找不到该应用", Toast.LENGTH_SHORT).show(); } else { startActivity(intent); } ``` ## 通过包名和Activity打开 **必要条件** 1、需要知道三方应用的包名和Activity名 2、三方应用清单文件中,目标Activity的属性`Export`需配置为`true` **打开方式** ```java Intent intent = new Intent(); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); ComponentName componentName = new ComponentName("com.mmbox.xbrowser.pro", "com.mmbox.xbrowser.BrowserActivity"); intent.setComponent(componentName); startActivity(intent); ``` 当目标应用不存在、目标Activity不存在、目标Activity未被设置为`Exported=true`时,会报如下错误: ```plain android.content.ActivityNotFoundException: Unable to find explicit activity class {xx.xx.xx/xx.xx.xxActivity}; have you declared this activity in your AndroidManifest.xml? ``` 因此启动前需进行判断: ```java Intent intent = new Intent(); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); ComponentName componentName = new ComponentName("com.mmbox.xbrowsesr.pro", "com.mmbox.xbrowser.BrowserActivity"); intent.setComponent(componentName); if (intent.resolveActivityInfo(getPackageManager(), PackageManager.MATCH_DEFAULT_ONLY) != null) { startActivity(intent); } else { Toast.makeText(context, "找不到应用", Toast.LENGTH_SHORT).show(); } ``` 此处不能使用Intent.resolveActivty方法判断,具体可参考后面的源码部分。 ## 隐式启动 **必要条件** 1、IntentFilter中至少有一个action,至少有一个Category,可没有Data和Type 2、如果有Data,参数中Data必须符合Data规则 3、Action和Category必须同时匹配Activity中的一个Action和一个Category **打开方式** ```java Uri uri = Uri.parse("http://www.baidu.com"); Intent intent = new Intent(Intent.ACTION_VIEW, uri); startActivity(intent); ``` 启动前需进行判断: ```java Uri uri = Uri.parse("http://www.baidu.com"); Intent intent = new Intent(Intent.ACTION_VIEW, uri); if (intent.resolveActivity(getPackageManager()) != null) { startActivity(intent); } else { Toast.makeText(context, "找不到应用", Toast.LENGTH_SHORT).show(); } ``` ## 源码分析 Intent的resolveActivity方法源码如下: ```java public ComponentName resolveActivity(@NonNull PackageManager pm) { if (mComponent != null) { return mComponent; } ResolveInfo info = pm.resolveActivity(this, PackageManager.MATCH_DEFAULT_ONLY); if (info != null) { return new ComponentName( info.activityInfo.applicationInfo.packageName, info.activityInfo.name); } return null; } ``` Intent的resolveActivityInfo方法源码如下: ```java public ActivityInfo resolveActivityInfo(PackageManager pm, @PackageManager.ComponentInfoFlags int flags) { ActivityInfo ai = null; if (mComponent != null) { ai = pm.getActivityInfo(mComponent, flags); } else { ResolveInfo info = pm.resolveActivity(this, PackageManager.MATCH_DEFAULT_ONLY | flags); if (info != null) { ai = info.activityInfo; } } return ai; } ``` resolveActivity和resolveActivityInfo两个方法名称相似,但是返回值却是不同的。前者返回的是ComponentName,后者返回的是ActivityInfo。在打开三方应用指定Activity时,需使用resolveActivityInfo方法进行判断。 # 总结 1、使用PackageManager.getLaunchIntentForPackage方法时,直接判断返回的Intent是否为空即可 2、使用Intent.setComponent方法时,需使用`Intent.resolveActivityInfo()`或者`packageManager.queryIntentActivities()`两种方式判断 3、隐式启动时,使用`Intent.resolveActivity()`、`Intent.resolveActivityInfo()`、`packageManager.queryIntentActivities()`三种方式均可 参考文档:[https://likfe.com/2017/08/30/android-is-intent-available/](https://likfe.com/2017/08/30/android-is-intent-available/)