今天有同学问我,android系统怎么指定分享的App,把其他不需要显示的App全部过滤掉.我想了下,设置Intent过滤规则就可以了.
先来看看基础知识点:
1 Intent 和 Intent 过滤器
https://developer.android.google.cn/guide/components/intents-filters
Intent 分为两种类型:
- 显式 Intent:按名称(完全限定类名)指定要启动的组件。 通常,您会在自己的应用中使用显式 Intent 来启动组件,这是因为您知道要启动的 Activity 或服务的类名。例如,启动新 Activity 以响应用户操作,或者启动服务以在后台下载文件。
- 隐式 Intent :不会指定特定的组件,而是声明要执行的常规操作,从而允许其他应用中的组件来处理它。 例如,如需在地图上向用户显示位置,则可以使用隐式 Intent,请求另一具有此功能的应用在地图上显示指定的位置。
图 1. 隐式 Intent 如何通过系统传递以启动其他 Activity 的图解:
[1] Activity A 创建包含操作描述的 Intent
,并将其传递给 startActivity()
。
[2] Android 系统搜索所有应用中与 Intent 匹配的 Intent 过滤器。 找到匹配项之后,
[3] 该系统通过调用匹配 Activity(Activity B)的 onCreate()
方法并将其传递给 Intent
,以此启动匹配 Activity。
2 基本的分享功能:
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_TITLE, title);
intent.putExtra(Intent.EXTRA_SUBJECT, subject);
intent.putExtra(Intent.EXTRA_TEXT, content);
Intent chooserIntent = Intent.createChooser(intent, "Select app to share");
if (chooserIntent == null) {
return;
}
try {
startActivity(chooserIntent);
} catch (android.content.ActivityNotFoundException ex) {
Toast.makeText(this, "Can't find share component to share", Toast.LENGTH_SHORT).show();
}
-
一般,通过上面的代码,提供的分享方式有各种应用:邮件,信息,蓝牙,微博,Twitter,二维码扫描器等。
3 分享策略
1 分享指定应用:
例如只分享到QQ,直接添加QQ的包名就好了
intent.setPackage("com.tencent.mobileqq");
如果分享的指定应用比较多,则可以使用集合将分别设置的Intent(此处每个包名都是一个新的Intent)添加到集合中,然后设置到Intent里面即可
例如,我写死了几个包名:
public void share(View view) {
List<Intent> targetedShareIntents = new ArrayList<Intent>();
for (int i = 0; i < 3; i++) {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.setType("image/jpeg");
intent.putExtra(Intent.EXTRA_TITLE, "标题");
intent.putExtra(Intent.EXTRA_SUBJECT, "内容");
intent.putExtra(Intent.EXTRA_TEXT, "哈哈哈哈哈哈");
if (i == 0) {
intent.setPackage("com.tencent.mobileqq");
} else if (i == 1) {
intent.setPackage("com.tencent.mm");
} else if (i == 2) {
intent.setPackage("com.sina.weibo");
}
targetedShareIntents.add(intent);
}
Intent chooserIntent = Intent.createChooser(targetedShareIntents.get(0), "Select app to share");
if (chooserIntent == null) {
return;
}
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetedShareIntents.toArray(new Parcelable[]{}));
// A Parcelable[] of Intent or LabeledIntent objects as set with
// putExtra(String, Parcelable[]) of additional activities to place
// a the front of the list of choices, when shown to the user with a
// ACTION_CHOOSER.
try {
startActivity(chooserIntent);
} catch (android.content.ActivityNotFoundException ex) {
Toast.makeText(this, "Can't find share component to share", Toast.LENGTH_SHORT).show();
}
}
2 分享到制定应用,每个应用分享的内容不一样
例如:过滤掉蓝牙,对邮件分享详细的内容,对信息和微博等分享较简短的内容,对二维码扫描器只分享URL。
解决的办法是得到所有能处理ACTION_SEND的应用程序包名,然后根据名字来过滤或者特殊处理。主要用到getPackageManager().queryIntentActivities方法。
String contentDetails = "";
String contentBrief = "";
String shareUrl = "";
Intent it = new Intent(Intent.ACTION_SEND);
it.setType("text/plain");
List<ResolveInfo> resInfo = getPackageManager().queryIntentActivities(it, 0);
if (!resInfo.isEmpty()) {
List<Intent> targetedShareIntents = new ArrayList<Intent>();
for (ResolveInfo info : resInfo) {
Intent targeted = new Intent(Intent.ACTION_SEND);
targeted.setType("text/plain");
ActivityInfo activityInfo = info.activityInfo;
// judgments : activityInfo.packageName, activityInfo.name, etc.
if (activityInfo.packageName.contains("bluetooth") || activityInfo.name.contains("bluetooth")) {
continue;
}
if (activityInfo.packageName.contains("gm") || activityInfo.name.contains("mail")) {
targeted.putExtra(Intent.EXTRA_TEXT, contentDetails);
} else if (activityInfo.packageName.contains("zxing")) {
targeted.putExtra(Intent.EXTRA_TEXT, shareUrl);
} else {
targeted.putExtra(Intent.EXTRA_TEXT, contentBrief);
}
targeted.setPackage(activityInfo.packageName);
targetedShareIntents.add(targeted);
}
Intent chooserIntent = Intent.createChooser(targetedShareIntents.remove(0), "Select app to share");
if (chooserIntent == null) {
return;
}
// A Parcelable[] of Intent or LabeledIntent objects as set with
// putExtra(String, Parcelable[]) of additional activities to place
// a the front of the list of choices, when shown to the user with a
// ACTION_CHOOSER.
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetedShareIntents.toArray(new Parcelable[] {}));
try {
startActivity(chooserIntent);
} catch (android.content.ActivityNotFoundException ex) {
Toast.makeText(this, "Can't find share component to share", Toast.LENGTH_SHORT).show();
}
}
参考自: http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2013/1005/1564.html
3 如何分享自己的app
例如,如果你创建了一个社交app可以分享信息和图片给用户的朋友,为了其他app可以启动activity,应该在manifest文件中添加<intent-filter>元素和响应的<activity>元素。
当app安装到设备上后,系统会识别intent filter然后把信息加到一个所有安装的app信息都存储在PackageManagerService中。
PKMS构造函数的主要功能是,扫描Android系统中几个目标文件夹中的APK,从而建立合适的数据结构以管理诸如Package信息、四大组件信息、权限信息等各种信息。抽象地看,PKMS像一个加工厂,它解析实际的物理文件(APK文件)以生成符合自己要求的产品。例如,PKMS将解析APK包中的AndroidManifest.xml,并根据其中声明的Activity标签来创建与此对应的对象并加以保管。
当app用模糊的intent调用startActivity()或者startActivityForResult()时,系统就会查询哪个activity(或哪些)可以响应这个intent。
Action
要指定的动作的名字。通常是平台预定义的值比如ACTION_SEND或者ACTION_VIEW。
Data
和intent相关的数据描述
在intent filter中的用<data>元素来指定。在这个元素中使用一个或多个属性,可以只指定MIME类型,URI前缀,或者这些和其他可接受数据类型的组合。
注意:如果不不声明数据Uri的细节(比如用户处理其他类型的数据,而不是URI),应该只指明android:mimeType属性来声明activity处理的数据类型,比如text/plain或image/jpeg。
Category
提供了一个附加的方式来表示activity处理的intent的特性,通常和用户手势或开始的位置相关。系统支持好几个不同的category,但是很少用到。但是,所有明确的intent都默认定义为CATEGORY_DEFAULT。
每个引入的intent都指定了一个动作类型和数据类型,但是可以定义多个<action>,<category>,和<data>元素在每个<intent-filter>中。
如果两组动作和数据在他们的行为中相互冲突,应该创建另外一个intent-filter来指明接收哪个操作时对应哪些数据类型。
例如,假如activity可以处理ACTION_SEND和ACTION_SENDTO intent以及字符串和图片。这种情况下,应该为这两个操作定义两个不同的intent filter,因为ACTION_SENDTO intent在用必须使用URI数据来指定收件人地址,例如:
1 <activity android:name="ShareActivity">
2 <!-- filter for sending text; accepts SENDTO action with sms URI schemes -->
3 <intent-filter>
4 <action android:name="android.intent.action.SENDTO"/>
5 <category android:name="android.intent.category.DEFAULT"/>
6 <data android:scheme="sms" />
7 <data android:scheme="smsto" />
8 </intent-filter>
9 <!-- filter for sending text or images; accepts SEND action and text or image data -->
10 <intent-filter>
11 <action android:name="android.intent.action.SEND"/>
12 <category android:name="android.intent.category.DEFAULT"/>
13 <data android:mimeType="image/*"/>
14 <data android:mimeType="text/plain"/>
15 </intent-filter>
16 </activity>
注意:为了可以接收模糊的intent,必须在intent filter中包括CATEGORY_DEFAULT。方法startActivity()和startActivityForResult()只处理带有CATEGORY_DEFAULT的intent。如果没有声明它,那么没有模糊的intent会传给你的activity。