Android必知必知——使用Intent打开第三方应用并验证可用性判断Intent能否解析可能遗漏的基础知识1.App的入口Activity及其图标一个普通的应用默认会有一个入口Activity,在AndroidManifest.xml中一般是这样写的:="android.intent.category.LAUNCHER"/>...只有配置了这样的Activity,应用程序才会知道点击时启动哪个Activity。如果把category的值改成android.intent.category.DEFAULT,那么应用就会在桌面上看不到图标,无法直接打开。使用Intent打开第三方应用或者指定一个Activity只知道包名——需要默认入口Activity才能启动指定第三方应用的Activity——需要包名和Activity名,Activity的Export="true"隐式启动第三方应用程序1.使用PackageManager.getLaunchIntentForPackage()Stringpackage_name="xx.xx.xx";PackageManagerpackageManager=context.getPackageManager();Intentit=packageManager.getLaunchIntentForPackage(package_name);startActivity(it);要在启动应用程序时使用,应用程序最大的限制是有一个默认入口Activity。当没有默认入口Activity时,会报NullPointerException:java.lang.NullPointerException:Attempttoinvokevirtualmethod'java.lang.Stringandroid.content.Intent.toString()'onanulobjectreference看getLaunchIntentForPackage()方法的说明:/***返回一个“好”意图启动包中的前门活动。*例如,这用于在浏览*通过包时实现“打开”按钮。当前实现首先查找类别中的主要活动{@linkIntent#CATEGORY_INFO},然后查找类别中的*主要活动{@linkIntent#CATEGORY_LAUNCHER}。返回<*null/code>ifneitherarefound.**@parampackageNameThenameofthepackagetoinspect.**@returnAfully-qualified{@linkIntent}thatcanbeusedtolaunchthe*mainactivityinthepackage.Returns
null
ifthepackage*doesnotcontainsuchanactivity,orifpackageName未*识别。*/publicabstractIntentgetLaunchIntentForPackage(StringpackageName);公共抽象意图getLaunchIntentForPackage(字符串包名);所以用这个方法判断Intent是否为空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);//可选ComponentNamecomp=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和TypeCategory必须同时匹配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.getLaunch)IntentForPackage(,直接判断返回的Intent是否为空;方法二:Intent.setComponent(),使用Intent.resolveActivityInfo()或packageManager.queryIntentActivities();方法三隐式启动,使用Intent.resolveActivity(),Intent.resolveActivityInfo()和packageManager.queryIntentActivities()可以通过三种方式使用。
