使用Intent打开第三方应用验证可用性分析中可能遗漏的地方基础知识1.App的入口Activity及其图标一个普通的应用默认会有一个入口Activity,在AndroidManifest.xml中一般这样写:null/code>ifneitherarefound.**@parampackageNameThenameofthepackagetoinspect.**@returnAfully-qualified{@linkIntent}thatcanbeusedtolaunchthe*mainactivityinthepackage.Returns
null
ifthepackage*doesnotcontainsuchanactivity,orifpackageName未*识别。*/publicabstractIntentgetLaunchIntentForPackage(StringpackageName);所以用这个方法来判断Intent是否为空。Stringpackage_name="xx.xx.xx";PackageManagerpackageManager=getPackageManager();Intentit=packageManager.getLaunchIntentForPackage(package_name);if(it!=null){startActivity(it);}else{//无默认入口Activity}2。使用Intent.setComponent()Stringpackage_name="xx.xx.xx";Stringactivity_path="xx.xx.xx.ab.xxActivity";Intentintent=newIntent();intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//OptionalComponentNamecomp=newComponentName(package_name,activity_path);intent.setComponent(comp);startActivity(intent);该方法可以启动一个应用程序指定的Activity,不限于默认入口Activity。不过这个方法需要的条件很多,如下:知道App的包名和Activity的完整路径,需要启动的目标Activity的名称。AndroidManifest.xml中的属性Export="true"。这样,如何判断目标Activity是否存在呢?下面是网上流传的一个很常见的用法:Stringpackage_name="xx.xx.xx";Stringactivity_path="xx.xx.xx.ab.xxActivity";Intentintent=newIntent();intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//OptionalComponentNamecn=newComponentName(package_name,activity_path);intent.setComponent(cn);if(intent.resolveActivity(getPackageManager())!=null){startActivity(intent);}else{//没有找到指定的Activity}遗憾的是,Intent.resolveActivity()方法无法判断该方法要启动的Activity是否存在。如果Activity不存在,会报java.lang.IllegalArgumentException:Unknowncomponent,程序崩溃。我们看一下resolveActivity()的代码,和它类似的方法resolveActivityInfo():!=null){returnnewComponentName(info.activityInfo.applicationInfo.packageName,info.activityInfo.name);}returnnull;}publicActivityInforesolveActivityInfo(PackageManagerpm,intflags){ActivityInfoai=null;if(mComponent!=null){try{ai=pm.getActivityInfo(mComponent,flags);}catch(PackageManager.NameNotFoundExceptione){//忽略}}else{ResolveInfoinfo=pm.resolveActivity(this,PackageManager.MATCH_DEFAULT_ONLY|flags);if(info!=null){ai=info.activityInfo;}}returnai;}很明显,我们的方法是先设置ComponentName,所以它会直接返回mComponent给我们,不需要任何判断逻辑。相比之下,resolveActivityInfo()可以进行有效判断,返回null。因此,我们选择使用Intent.resolveActivityInfo()这样判断:Stringpackage_name="xx.xx.xx";Stringactivity_path="xx.xx.xx.ab.xxActivity";Intentintent=newIntent();intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//可选ComponentNamecn=newComponentName(package_name,activity_path);intent.setComponent(cn);if(intent.resolveActivityInfo(getPackageManager(),PackageManager.MATCH_DEFAULT_ONLY)!=null){startActivity(intent);}else{//找不到指定的Activity}3.隐式启动第三方应用该方法多用于启动系统中的功能性应用,如拨打电话、发送邮件、预览图片等,使用默认浏览器打开网页等。>Intentintent=newIntent();>intent.setAction(action);>intent.addCategory(类别);>intent.setDataAndType("abc://www.dfg.com","image/gif");>startActivity(intent);>条件1:IntentFilter至少有一个action和至少一个Category,可以没有Data和Type条件2:如果有Data,则参数中的Data必须满足Data规则条件3:Action和Category必须同时匹配Activity中的一个Action和一个Category(Category默认:android.intent.category.DEFAULT)有很多隐含的启动函数,就不一一列举了。需要的时候可以直接搜索相关代码。我们以打开一个网页为例:Uriuri=Uri.parse("http://www.abc.xyz");Intentintent=newIntent(Intent.ACTION_VIEW,uri);startActivity(intent);这时候直接使用Intent.resolveActivity()方法就没有问题了:Uriuri=Uri.parse("http://www.abc.xyz");Intentintent=newIntent(Intent.ACTION_VIEW,uri);if(intent.resolveActivity(getPackageManager())!=null){startActivity(intent);}else{//NoneInstalltherequiredapplication}总结看了PackageManager的代码,发现packageManager.queryIntentActivities()方法可以用于判断系统中是否存在可以解析指定Intent的应用。publicbooleanisAvailable(Contextcontext,Intentintent){PackageManagerpackageManager=context.getPackageManager();Listlist=packageManager.queryIntentActivities(intent,PackageManager.MATCH_DEFAULT_ONLY);returnlist.size()>0;}那么,总结就是:方式一PackageManager.getLaunchIntentForPackage(),直接判断返回的Intent是否为空;方法二:Intent.setComponent(),使用Intent.resolveActivityInfo()或packageManager.queryIntentActivities();方法三隐式启动,使用Intent.resolveActivity()、Intent.resolveActivityInfo()和packageManager.queryIntentActivities()三种方式可以使用。
