APP分享功能的实现
Contents
说起在APP中添加分享功能,也在项目开发中集成过第三方的社会化组件,功能做出来了之后就发现坑其实挺多的,比如APP体积增加3~4MB,微信、微博等社区集成都需要申请appkey等。当然,一般第三方的社会化组件往往不只是集成分享功能,还会集成账号授权登陆等,而系统的分享功能就比较单纯了。这两天学习了一下系统自带的分享功能,写一篇笔记记录一下。
通过Intent向其他应用发送分享内容
先看一下发送邮件的Intent:
Intent intent = new Intent(Intent.ACTION_SENDTO);
intent.setData(Uri.parse("mailto:artharyoungcn@gmail.com"));
intent.putExtra(Intent.EXTRA_SUBJECT, "title");
intent.putExtra(Intent.EXTRA_TEXT, "desc");
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
如果手机上已经安装了邮件的客户端,这个Intent将匹配action直接拉起邮件客户端。
分享文本的Intent:
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_TEXT, "send message to someone");
intent.setType("text/plain");
startActivity(intent);
一般我们使用的手机上能匹配这个action的app都不止一个,QQ、微信、微博,这些社交类应用自不必说。蓝牙,NFC等一般也都会匹配这个action。所以系统会显示一个对话框供用户选择,并且会提示用户设置默认分享的APP,个人认为这个并没有什么用,因为我们无法保证用户每一次都分享到同一个app.我们可以使用Intent.createChooser()来设置弹出框的标题,并保证每次都弹出选择框,即使设置了默认分享。
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_TEXT, "send message to someone");
intent.setType("text/plain");
startActivity(Intent.createChooser(intent, "实现分享"));
以上只是分享文本,在实际的开发过程中往往还需要分享图片。
数据流分享(这里以图片分享为例)
Bitmap bm = BitmapFactory.decodeResource(getResources(),R.drawable.chrome);
String path = MediaStore.Images.Media.insertImage(getContentResolver(), bm, "", "desc");
Uri imageUri = Uri.parse(path);
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_STREAM, imageUri);
intent.setType("image/*");
startActivity(Intent.createChooser(intent, "实现分享"));
这里需要提供一个供第三方程序访问的Uri,一般有以下几个方案:
- 把数据写到外部存储(SD卡)上,使用Uri.fromFile()创建一个file://形式的Uri。 这个形式的Uri并不是所有程序都能处理。
- 在自己程序文件夹下用MODE_WORLD_READABLE模式使用openFileOutput()把数据写入文件, 之后再用getFileStreamPath()返回一个File。用Uri.fromFile()来创建一个file://样式的Uri。
- 图片,音频,视频等媒体文件可以用scanFile()扫描然后加到系统媒体库(MediaStore)中, onScanCompleted()回调方法会返回一个content://样式的Uri。
- 图片还可以用insertImage()来加到媒体库(MediaStore)中,然后会返回一个content://样式的Uri。
- 在ContentProvider中保存数据,给其他APP提供访问权限。
这里我们稍微对比下友盟社会化组件的存储方式,在UMImage.class这个类里面可以发现它在SD卡上自己创建了一个缓存文件夹:
public File getCache() throws IOException {
String var1;
if(DeviceConfig.isSdCardWrittenable()) {
var1 = Environment.getExternalStorageDirectory().getCanonicalPath();
} else {
if(TextUtils.isEmpty(this.b)) {
throw new IOException("dirpath is unknow");
}
var1 = this.b;
}
File var2 = new File(var1 + "/umeng_cache/");
if(var2 != null && !var2.exists()) {
var2.mkdirs();
}
return var2;
}
这里需要添加SD卡的读写权限:
<!-- 在SDCard中创建与删除文件权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<!-- 往SDCard写入数据权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
分享多条数据
ArrayList<Uri> imageUris = new ArrayList<Uri>();
imageUris.add(imageUri); // Add your image URIs here
imageUris.add(imageUri);
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND_MULTIPLE);
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, imageUris);
intent.setType("image/*");
startActivity(Intent.createChooser(intent, "分享图片"));
这里为了方便仍然使用上面的uri,只不过add了两次。
以上,都是通过给Intent设置一些其他信息:EXTRA_TEXT,EXTRA_STREAM等,并可以设置MIME(多用途互联网邮件扩展)类型。来达到让第三方客户端进行资源匹配的目的。但是,第三方程序需要能够解析他们,如果我们自定义extras,基本是实现不了分享的。我们可以来看一下如何接收其他APP发过来的分享。
接收其他APP的分享内容
- 在manifest文件中配置filter。比如我们在demo的MainActivity中配置:
```java
再次运行的时候会发现分享的列表中多了demo这个APP。
- 处理传入的数据
```java
Intent intent = getIntent();
String action = intent.getAction();
String type = intent.getType();
拿到action和MIME类型,然后就该干嘛干嘛去了~这里需要注意的是,我们不知道用户传进来的是什么,用户也有可能传错了MIME类型,还有可能传进来的数据非常大,比如一张特别大的图片。所以数据不建议放在UI线程中处理。
使用ShareActionProvider分享数据
ShareActionProvider是在API等级14以后提供的一种分享方式,与上面的分享对比如下: {% img /images/20160531090856.jpg %}
可以发现在UI的显示上还是有很大区别的,ShareActionProvider将分享放在在ActionBar上。使用方法需要现在menu菜单中添加item:
<item android:id="@+id/action_share"
app:showAsAction="never"
android:title="@string/action_share"
app:actionProviderClass="android.support.v7.widget.ShareActionProvider" />
然后在onCreateOptionsMenu回调中获取ShareActionProvider:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
MenuItem item = menu.findItem(R.id.action_share);
mShareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(item);
return true;
}
通过mShareActionProvider.setShareIntent(intent)设置需要分享的内容,intent的设置方式与前面是一样的。
这里有个坑需要注意下,我在demo中使用的是AppCompatActivity,是在appcompat-v7包中的,它使用的也是这个包中的ActionBar。在Menu菜单中需要配置:
app:actionProviderClass="android.support.v7.widget.ShareActionProvider"
在Activity中import android.support.v7.widget.ShareActionProvider并使用MenuItemCompat.getActionProvider(item)的方式获取ShareActionProvider。 若不使用appcompat-v7包中的ActionBar,则Menu菜单中设置如下:
<item android:id="@+id/action_share"
android:showAsAction="ifRoom"
android:title="Share"
android:actionProviderClass="android.widget.ShareActionProvider" />
然后在onCreateOptionsMenu中,通过一下方式获取ShareActionProvider:
mShareActionProvider = (ShareActionProvider) item.getActionProvider();
然后就可以通过setShareIntent(intent)分享了。
Author artharyoung
LastMod 2016-06-04