Android-系统分享使用小结
概述
说到分享,有很多第三方的SDK可供使用,比如友盟,mob都很好用。虽然集成相对容易,但是需要针对每个平台申请APPID 。所以在对应用分享需求不是很强烈,对分享界面要求不大的时候使用系统自带的分享功能足以满足需求,当然如果要保证各个手机上的界面统一,那么第三方的SDK是最好的选择。下面就记录一下自己在实现系统分享时所遇到的问题,和实现步骤。
如何进行分享
系统分享通过调用Intent.createChooser方法构建一个分享界面,核心代码如下:
Intent intent = new Intent(Intent.ACTION_SEND);//设置分享行为
intent.setType("*/*");//设置分享内容的类型mime
/**
* 添加分享内容
* 注意:单个文件ACTION_SEND调用{@link Intent#putExtra}方法,
* 多个ACTION_SEND_MULTIPLE调用{@link Intent#putParcelableArrayListExtra}法
*/
//intent.putExtra(Intent.EXTRA_SUBJECT, contentTitle);//添加分享内容标题
//intent.putExtra(Intent.EXTRA_TEXT, content);//添加分享内容
intent.putExtra(Intent.EXTRA_STREAM,data);//传递分享数据
//创建分享界面
intent = Intent.createChooser(intent , title);//title为分享界面的标题
activity.startActivity(intent);
说明:
- 第一行设置分享行为,单个图片文件为Intent.ACTION_SEND,多个为Intent.ACTION_SEND_MULTIPLE
- 第二行设置分享类型,其中mime类型介绍详见 android之MIME
- 上述代码中的data为uri类型,传递图片时注意对路径进行转化
上述代码运行结果大致如下图:
如何筛选分享项
第一步做完了,那如何过滤掉不需要的分享渠道呢?下面给出一个分享图片的例子(只留下微信分享渠道),部分代码参考了自导自演的机器人,感谢
/**
* 分享图片(触发场景单个)
* @param context 上下文
*/
public void shareSingleImage(Context context) {
Intent intent = new Intent(Intent.ACTION_SEND);
//获取选中图片
Uri imageUri = Uri.parse("file://"+imagepath.toString());
// Log.d("resolveInfos","imageUri--->" + imageUri);
intent.setType("image/*");//设置mime格式为图片
//查询所有可以分享的activity
//进行筛选
List<ResolveInfo> resolveInfos = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
List<Intent> targetShareIntents = new ArrayList<>();
if (!resolveInfos.isEmpty()){
//过滤选择非邮件应用
for (ResolveInfo resolveInfo : resolveInfos){
Intent target = new Intent(Intent.ACTION_SEND);//设置分享行为 单个文件、图片
/**
* 添加分享内容
* 注意:单个文件ACTION_SEND调用{@link Intent#putExtra}方法,
* 多个ACTION_SEND_MULTIPLE调用{@link Intent#putParcelableArrayListExtra}方法
*/
target.putExtra(Intent.EXTRA_STREAM,imageUri);
target.setType("image/*");//设置分享内容mime类型
ActivityInfo activityInfo = resolveInfo.activityInfo;
PackageManager pm = ((Activity)context).getApplication().getPackageManager();
//打印所有符合条件的APP
Log.d("resolveInfos","packageName--->" + activityInfo.packageName + " name--->" + activityInfo.name+" label--->"+activityInfo.applicationInfo.loadLabel(pm).toString()+" activity label--->"+activityInfo.loadLabel(pm).toString()+" intent-filter label--->"+resolveInfo.loadLabel(pm).toString());
/**
* 获取activityinfo类中的基本信息 如 包名 activity名称,应用label activity label等
* {@link activityInfo.packageName} 应用包名,对应{@link applicationId 属性}
* {@link activityInfo.name} activity名称,对应{@link <activity>}中的{@linkplain android:name 属性}
* {@link activityInfo.applicationInfo.loadLabel(pm)}; 应用名称,对应{@link <application>}中的{@linkplain android:label 属性}
* {@link activityInfo.loadLabel(pm)}; activity名称(未设置默认为应用名称),对应{@link <activity>}中的{@linkplain android.label属性}
* {@link resolveInfo.loadLabel(pm)}; intent名称(未设置默认为前两个中优先级高的),对应{@link <intent-filter>}中的{@linkplain android:label属性}
*/
//微信
if (activityInfo.packageName.contains(ShareVariables.WECHAT)){
target.setPackage(activityInfo.packageName);
target.setClassName(activityInfo.packageName, activityInfo.name);
/**
* 由于直接传递intent 会导致微信QQ等部分(为intent-filter设置标签)的APP标签,在分享途径中丢失
* (很多应用是为activity设置label,并没有为intent-filter设置标签),
* 所以需要为传递intent的添加筛选出的标签。
*/
targetShareIntents.add(target);
}
}
Intent chooseIntent = Intent.createChooser(targetIntents.remove(0),null);
if (chooseIntent == null) {
return;
}
chooseIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS,targetIntents.toArray(new Parcelable[]{}));
//startActivityForResult(Intent.createChooser(intent, "选择应用"), 1001);;
try {
context.startActivity(chooseIntent);
} catch (android.content.ActivityNotFoundException ex) {
Toast.makeText(context, "找不到该分享应用组件", Toast.LENGTH_SHORT).show();
}
}
}
运行结果如下图所示
我们会发现满足了我们的要求,但是如何区分微信应用下的微信收藏,微信朋友,朋友圈呢?还有为什么之前显示的“发送给朋友”等不同字样都变成了微信呢?下面先解决第一个问题
如何区分部分APP下不同分享界面(以微信为例)
自导自演的机器人文章中通过标签解决了这个问题。因为每个activity都有自己的标签。但是这样指定在不同语言下会很麻烦。
下面给出自己的解决方法,首先贴一下之前代码打印出的log信息(部分)
我们可以通过activityInfo.name属性来区分不同的界面
如何还原过滤前APP分享途径的描述
在上一步的截图中我们发现朋友圈,微信,微信收藏的描述都变成了微信,那么如何变成过滤之前的描述呢?下面先来说明一下出现该问题的原因:
1、当我们执行
target.setPackage(activityInfo.packageName);
target.setClassName(activityInfo.packageName, activityInfo.name);
时,会将AndroidManufest文件中的activity标签中的label属性设置为分享渠道下的文字描述。而label属性的优先级为 application <activity<intent-filter 优先级高的标签中未设置label属性会默认只用上一级标签中的label属性
再看一下log
这里我们可以看到,微信没有为activity设置标签,默认显示为application的标签值,所以出现了上图所示的情况
解决方案:
我们需要将符合筛选条件的intent 设置label值。于是上网查找相应方法,结果没有找到。于是自己去intent类中寻找结果。找了半天没有找到如何为intent添加标签。于是寻找开发文档。果然在文档中找到了答案。intent 有个直接子类LabeledIntent 可以为其设置标签。通过其构造方法LabeledIntent(Intent origIntent, String sourcePackage,
CharSequence nonLocalizedLabel, int icon)设置标签
代码如下:
/**
* 分享图片(触发场景单个)
* @param context 上下文
*/
public void shareSingleImage(Context context) {
Intent intent = new Intent(Intent.ACTION_SEND);
//获取选中图片
Uri imageUri = Uri.parse("file://"+imagepath.toString());
// Log.d("resolveInfos","imageUri--->" + imageUri);
intent.setType("image/*");//设置mime格式为图片
//查询所有可以分享的activity
//进行筛选
List<ResolveInfo> resolveInfos = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
List<LabeledIntent> targetShareIntents = new ArrayList<>();
if (!resolveInfos.isEmpty()){
//过滤选择非邮件应用
for (ResolveInfo resolveInfo : resolveInfos){
Intent target = new Intent(Intent.ACTION_SEND);//设置分享行为 单个文件、图片
/**
* 添加分享内容
* 注意:单个文件ACTION_SEND调用{@link Intent#putExtra}方法,
* 多个ACTION_SEND_MULTIPLE调用{@link Intent#putParcelableArrayListExtra}方法
*/
target.putExtra(Intent.EXTRA_STREAM,imageUri);
target.setType("image/*");//设置分享内容mime类型
ActivityInfo activityInfo = resolveInfo.activityInfo;
PackageManager pm = ((Activity)context).getApplication().getPackageManager();
//打印所有符合条件的APP
Log.d("resolveInfos","packageName--->" + activityInfo.packageName + " name--->" + activityInfo.name+" label--->"+activityInfo.applicationInfo.loadLabel(pm).toString()+" activity label--->"+activityInfo.loadLabel(pm).toString()+" intent-filter label--->"+resolveInfo.loadLabel(pm).toString());
/**
* 获取activityinfo类中的基本信息 如 包名 activity名称,应用label activity label等
* {@link activityInfo.packageName} 应用包名,对应{@link applicationId 属性}
* {@link activityInfo.name} activity名称,对应{@link <activity>}中的{@linkplain android:name 属性}
* {@link activityInfo.applicationInfo.loadLabel(pm)}; 应用名称,对应{@link <application>}中的{@linkplain android:label 属性}
* {@link activityInfo.loadLabel(pm)}; activity名称(未设置默认为应用名称),对应{@link <activity>}中的{@linkplain android.label属性}
* {@link resolveInfo.loadLabel(pm)}; intent名称(未设置默认为前两个中优先级高的),对应{@link <intent-filter>}中的{@linkplain android:label属性}
*/
//微信
if (activityInfo.packageName.contains(ShareVariables.WECHAT)){
target.setPackage(activityInfo.packageName);
target.setClassName(activityInfo.packageName, activityInfo.name);
/**
* 由于直接传递intent 会导致微信QQ等部分(为intent-filter设置标签)的APP标签,在分享途径中丢失
* (很多应用是为activity设置label,并没有为intent-filter设置标签),
* 所以需要为传递intent的添加筛选出的标签。
*/
LabeledIntent targeted = new LabeledIntent(target,activityInfo.packageName,resolveInfo.loadLabel(pm),resolveInfo.icon);
targetShareIntents.add(targeted);
}
}
Intent chooseIntent = Intent.createChooser(targetIntents.remove(0),null);
if (chooseIntent == null) {
return;
}
chooseIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS,targetIntents.toArray(new Parcelable[]{}));
//startActivityForResult(Intent.createChooser(intent, "选择应用"), 1001);;
try {
context.startActivity(chooseIntent);
} catch (android.content.ActivityNotFoundException ex) {
Toast.makeText(context, "找不到该分享应用组件", Toast.LENGTH_SHORT).show();
}
}
}
结果如下图所示: