版权声明:本文为HaiyuKing原创文章,转载请注明出处!
前言
根据参考资料的文章,整理了调用系统自带分享的工具类(实现了适配7.0FileProvider的功能),需要搭配《Android6.0运行时权限(基于RxPermission开源库)》。
效果图
代码分析
需要注意的代码主要包括:
ShareIntentUtil中适配7.0FileProvider的相关代码。
使用步骤
一、项目组织结构图
注意事项:
1、 导入类文件后需要change包名以及重新import R文件路径
2、 Values目录下的文件(strings.xml、dimens.xml、colors.xml等),如果项目中存在,则复制里面的内容,不要整个覆盖
二、导入步骤
(1)将ShareIntentUtil.java文件复制到项目中
package com.why.project.sharewithsystemdemo.util; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Build; import android.support.v4.content.FileProvider; import android.widget.Toast; import java.io.File; import java.util.ArrayList; /** * Created by haiyuKing * Used 调用系统自带的分享的工具类 * 增加适配7.0FileProvider的功能 */ public class ShareIntentUtil { //指定分享到的软件包名 public static final String PACKAGE_QQ = "com.tencent.mobileqq";//分享到QQ public static final String PACKAGE_QZONE = "com.qzone";//分享会到QQ空间 public static final String PACKAGE_WBLOG = "com.tencent.WBlog";//分享到腾讯微博 public static final String PACKAGE_WXIN = "com.tencent.mm";//分享到微信 public static final String PACKAGE_WEIBO = "com.sina.weibo";//分享到新浪微博 public static final String PACKAGE_BAIDUYUN = "com.baidu.netdisk";//分享到百度云 //分享文本 public static void shareText(Context mContext, String shareText, String shareTitle){ Intent shareIntent = new Intent(Intent.ACTION_SEND); shareIntent.setType("text/plain"); shareIntent.putExtra(Intent.EXTRA_TEXT, shareText); //适配7.0FileProvider if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//添加这一句表示对目标应用临时授权该Uri所代表的文件【很重要】 } mContext.startActivity(Intent.createChooser(shareIntent, shareTitle));//可以设置标题 } //分享文本到指定应用 public static void shareTextTo(Context mContext, String shareText, String shareTitle, String packageName){ Intent shareIntent = new Intent(Intent.ACTION_SEND); shareIntent.setPackage(packageName); shareIntent.setType("text/plain"); shareIntent.putExtra(Intent.EXTRA_TEXT, shareText); //适配7.0FileProvider if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//添加这一句表示对目标应用临时授权该Uri所代表的文件【很重要】 } //通过Intent的resolveActivity方法,并想该方法传入包管理器可以对包管理器进行查询以确定是否有Activity能够启动该Intent //https://blog.csdn.net/qq_15796477/article/details/72953514 PackageManager pm = mContext.getPackageManager(); ComponentName cn = shareIntent.resolveActivity(pm); if(cn == null){ Toast.makeText(mContext,"未安装该应用",Toast.LENGTH_SHORT).show(); }else { mContext.startActivity(Intent.createChooser(shareIntent, shareTitle));//可以设置标题 } } //分享单张图片 public static void shareOneImg(Context mContext, String imgPath, String shareTitle){ File file = new File(imgPath); if (!file.exists()) { Toast.makeText(mContext,"文件不存在",Toast.LENGTH_SHORT).show(); return; } //由文件得到uri Uri imageUri = getUri(mContext,file); Intent shareIntent = new Intent(); shareIntent.setAction(Intent.ACTION_SEND); shareIntent.putExtra(Intent.EXTRA_STREAM, imageUri); shareIntent.setType("image/*"); //适配7.0FileProvider if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//添加这一句表示对目标应用临时授权该Uri所代表的文件【很重要】 } mContext.startActivity(Intent.createChooser(shareIntent, shareTitle));//可以设置标题 } //分享多张图片 public static void shareMultImg(Context mContext, ArrayList<String> imgPathList, String shareTitle){ ArrayList<Uri> uriList = new ArrayList<>(); for(int i=0;i<imgPathList.size();i++){ File file = new File(imgPathList.get(i)); if (!file.exists()) { Toast.makeText(mContext,"文件不存在",Toast.LENGTH_SHORT).show(); return; } uriList.add(getUri(mContext,file)); } Intent shareIntent = new Intent(); shareIntent.setAction(Intent.ACTION_SEND_MULTIPLE); shareIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uriList); shareIntent.setType("image/*"); //适配7.0FileProvider if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//添加这一句表示对目标应用临时授权该Uri所代表的文件【很重要】 } mContext.startActivity(Intent.createChooser(shareIntent, shareTitle));//可以设置标题 } //分享单个文件 public static void shareOneFile(Context mContext, String filePath, String shareTitle){ File file = new File(filePath); if (!file.exists()) { Toast.makeText(mContext,"文件不存在",Toast.LENGTH_SHORT).show(); return; } //由文件得到uri Uri fileUri = getUri(mContext,file); Intent shareIntent = new Intent(); shareIntent.setAction(Intent.ACTION_SEND); shareIntent.putExtra(Intent.EXTRA_STREAM, fileUri); shareIntent.setType("*/*"); //适配7.0FileProvider if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//添加这一句表示对目标应用临时授权该Uri所代表的文件【很重要】 } mContext.startActivity(Intent.createChooser(shareIntent, shareTitle));//可以设置标题 } //获取到uri--适配7.0FileProvider private static Uri getUri(Context mContext, File file){ Uri uri; if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { String authority = mContext.getApplicationInfo().packageName + ".provider"; uri = FileProvider.getUriForFile(mContext.getApplicationContext(), authority, file); //intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//添加这一句表示对目标应用临时授权该Uri所代表的文件【很重要】 } else { uri = Uri.fromFile(file); } return uri; } }
(2)在AndroidManifest.xml中添加权限以及配置7.0FileProvider【注意:provider中的android:authorities值:${applicationId}.provider,其中${applicationId}代表的真实值就是APP的build.gradle中的applicationId(包名)值】
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.why.project.sharewithsystemdemo"> <!-- =================ShareIntentUtil用到的权限========================== --> <!-- 允许程序读取外部存储文件 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <!-- =================7.0上读取文件========================== --> <!--参考资料https://blog.csdn.net/lmj623565791/article/details/72859156--> <!--authorities:{app的包名}.provider grantUriPermissions:必须是true,表示授予 URI 临时访问权限 exported:必须是false resource:中的@xml/provider_paths是我们接下来要添加的文件--> <provider android:name="android.support.v4.content.FileProvider" android:authorities="${applicationId}.provider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths"/> </provider> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
(3)将provider_paths文件复制到项目的res/xml目录下【适配7.0FileProvider】
<?xml version="1.0" encoding="utf-8"?> <!--参考资料https://blog.csdn.net/lmj623565791/article/details/72859156--> <!--<root-path/> 代表设备的根目录new File("/");--> <!--<files-path/> 代表context.getFilesDir()--> <!--<cache-path/> 代表context.getCacheDir()--> <!--<external-path/> 代表Environment.getExternalStorageDirectory()--> <!--<external-files-path>代表context.getExternalFilesDirs()--> <!--<external-cache-path>代表getExternalCacheDirs()--> <!--path:需要临时授权访问的路径(.代表所有路径)--> <!--name:就是你给这个访问路径起个名字--> <paths> <root-path name="root" path="." /> <files-path name="files" path="." /> <cache-path name="cache" path="." /> <external-path name="external" path="." /> <external-files-path name="external_file_path" path="." /> <external-cache-path name="external_cache_path" path="." /> </paths>
(4)参考《Android6.0运行时权限(基于RxPermission开源库)》导入相关文件。
三、使用方法
布局文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:gravity="center"> <Button android:id="@+id/btn_share_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="分享文本" android:layout_marginTop="10dp"/> <Button android:id="@+id/btn_share_one_img" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="分享单张图片" android:layout_marginTop="10dp"/> <Button android:id="@+id/btn_share_mult_img" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="分享多张图片" android:layout_marginTop="10dp"/> <Button android:id="@+id/btn_share_to_qq" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="分享到qq" android:layout_marginTop="10dp"/> <Button android:id="@+id/btn_share_one_file" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="分享单个文件" android:layout_marginTop="10dp"/> </LinearLayout>
在Activity中使用【先申请权限,然后执行相关方法:注意,Demo中指定了文件路径,实际项目中一般是动态获取的】
package com.why.project.sharewithsystemdemo; import android.Manifest; import android.os.Bundle; import android.os.Environment; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.Toast; import com.tbruyelle.rxpermissions2.RxPermissions; import com.why.project.sharewithsystemdemo.util.ShareIntentUtil; import java.io.File; import java.util.ArrayList; import io.reactivex.functions.Action; import io.reactivex.functions.Consumer; public class MainActivity extends AppCompatActivity { private static final String TAG = MainActivity.class.getSimpleName(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); onePermission(); initEvents(); } private void initEvents() { //分享文本 findViewById(R.id.btn_share_text).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { ShareIntentUtil.shareText(MainActivity.this,"这是一段分享的文字","分享文本"); } }); //分享单张图片 findViewById(R.id.btn_share_one_img).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //Environment.getExternalStorageDirectory()=/storage/emulated/0 Log.e("why","Environment.getExternalStorageDirectory()="+Environment.getExternalStorageDirectory()); String imagePath = Environment.getExternalStorageDirectory() + File.separator + "DCIM/Camera/IMG_20160723_103940.jpg"; ShareIntentUtil.shareOneImg(MainActivity.this,imagePath,"分享单张图片"); } }); //分享多张图片 findViewById(R.id.btn_share_mult_img).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //Environment.getExternalStorageDirectory()=/storage/emulated/0 Log.e("why","Environment.getExternalStorageDirectory()="+Environment.getExternalStorageDirectory()); ArrayList<String> imgPathList = new ArrayList<>(); String path = Environment.getExternalStorageDirectory() + File.separator; imgPathList.add(path+"DCIM/Camera/IMG_20160723_103940.jpg"); imgPathList.add(path+"DCIM/Camera/IMG_20170820_121408.jpg"); imgPathList.add(path+"DCIM/Camera/IMG_20171001_080012.jpg"); ShareIntentUtil.shareMultImg(MainActivity.this,imgPathList,"分享多张图片"); } }); //分享到qq findViewById(R.id.btn_share_to_qq).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { ShareIntentUtil.shareTextTo(MainActivity.this,"这是一段分享的文字","分享到QQ",ShareIntentUtil.PACKAGE_QQ); } }); //分享单个文件 findViewById(R.id.btn_share_one_file).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //Environment.getExternalStorageDirectory()=/storage/emulated/0 Log.e("why","Environment.getExternalStorageDirectory()="+Environment.getExternalStorageDirectory()); String filePath = Environment.getExternalStorageDirectory() + File.separator + "why/AndroidNotesForProfessionals.pdf"; ShareIntentUtil.shareOneFile(MainActivity.this,filePath,"分享单个文件"); } }); } /**只有一个运行时权限申请的情况*/ private void onePermission(){ RxPermissions rxPermissions = new RxPermissions(MainActivity.this); // where this is an Activity instance rxPermissions.request(Manifest.permission.READ_EXTERNAL_STORAGE) //权限名称,多个权限之间逗号分隔开 .subscribe(new Consumer<Boolean>() { @Override public void accept(Boolean granted) throws Exception { Log.e(TAG, "{accept}granted=" + granted);//执行顺序——1【多个权限的情况,只有所有的权限均允许的情况下granted==true】 if (granted) { // 在android 6.0之前会默认返回true // 已经获取权限 Toast.makeText(MainActivity.this, "已经获取权限", Toast.LENGTH_SHORT).show(); } else { // 未获取权限 Toast.makeText(MainActivity.this, "您没有授权该权限,请在设置中打开授权", Toast.LENGTH_SHORT).show(); } } }, new Consumer<Throwable>() { @Override public void accept(Throwable throwable) throws Exception { Log.e(TAG,"{accept}");//可能是授权异常的情况下的处理 } }, new Action() { @Override public void run() throws Exception { Log.e(TAG,"{run}");//执行顺序——2 } }); } }
混淆配置
无