Android系统分享使用Intent分享文本到QQ和文本+图片到微信朋友圈及纯图到微信

本文对应的Git项目

本文主要介绍以下功能:

简单说明-也是我当时需要要做出来的效果:

1.QQ:分享到QQ好友时,直接以发文本的方式分享出去,字数不受限制
2.WechatMoment : 分享到微信朋友圈时,需要将图片带到发送朋友圈图文发送界面直接发送分享(新版微信不支持同时带文本)
3.直接分享图片给微信好友

说到分享许多人都会使用一些第三方sdk来实现,比如“友盟分享”,“Mob分享(ShareSdk)”。

这两种分享方式需要配置许多文件和代码,虽说省去了我们一个个集成各大网站分享的sdk,但常常也会自带许多坑,具体的大家在使用的时候就会发现,我就不评价了。

QQ分享:无论是友盟或sharesdk,都无法实现直接将长文本分享到QQ好友,原因是什么?我找过他们客服,这是tencent(腾讯)公司分享sdk规定的。具体可查看:链接中的 1.13 分享消息到QQ(无需QQ登录)的参数,以QQapi上的代码进行分享以后除了文本字数有限制以外,而且其分享的样式是以链接的形式分享出去的,所以不符合我的要求。

WechatMoment微信朋友圈分享:以官方文档或以第三方通道分享时,在分享到朋友圈的时候,分享文本是设置不到文本区域的,无论你用啥方法。因为ShareSdk官方文档也说了:查看第4点(微信(好友、朋友圈、收藏))当你需要同时设置分享图片和文本时你设置的text是不显示的。

我的解决方案:(使用Intent分享)但有个缺点是,分享到平台后却不能返回到原应用,只能留在QQ或微信(除在微信分享文件-分享文件给好友可以返回到原应用)

先给大家提供个判断QQ向微信客户端是否存在的两个方法:
调用方式如:Platformutil.isInstallApp(context,PlatformUtil.PACKAGE_WECHAT);// 判断微信是否安装

public class PlatformUtil {
    public static final String PACKAGE_WECHAT = "com.tencent.mm";
    public static final String PACKAGE_MOBILE_QQ = "com.tencent.mobileqq";
    public static final String PACKAGE_QZONE = "com.qzone";
    public static final String PACKAGE_SINA = "com.sina.weibo";

    // 判断是否安装指定app
    public static boolean isInstallApp(Context context, String app_package){
        final PackageManager packageManager = context.getPackageManager();
        List<PackageInfo> pInfo = packageManager.getInstalledPackages(0);
        if (pInfo != null) {
            for (int i = 0; i < pInfo.size(); i++) {
                String pn = pInfo.get(i).packageName;
                if (app_package.equals(pn))) {
                    return true;
                }
            }
        }
        return false;
    }
}

QQ分享(分享至QQ好友或群组):

   /**
     * 直接分享纯文本内容至QQ好友
     * @param mContext
     * @param content
     */
    public static void shareQQ(Context mContext, String content) {
        if (Platformutil.isInstallApp(mContext,PlatformUtil.PACKAGE_MOBILE_QQ)) {
            Intent intent = new Intent("android.intent.action.SEND");
            intent.setType("text/plain");
            intent.putExtra(Intent.EXTRA_SUBJECT, "分享");
            intent.putExtra(Intent.EXTRA_TEXT, content);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.setComponent(new ComponentName("com.tencent.mobileqq", "com.tencent.mobileqq.activity.JumpActivity"));
            mContext.startActivity(intent);
        } else {
            Toast.makeText(mContext, "您需要安装QQ客户端", Toast.LENGTH_LONG).show();
        }
    }

 /**
     * 分享图片给QQ好友
     *
     * @param bitmap
     */
    public void shareImageToQQ(Bitmap bitmap) {
        if (Platformutil.isInstallApp(mContext,PlatformUtil.PACKAGE_MOBILE_QQ)) {
            try {
                Uri uriToImage = Uri.parse(MediaStore.Images.Media.insertImage(
                        mContext.getContentResolver(), bitmap, null, null));
                Intent shareIntent = new Intent();
                shareIntent.setAction(Intent.ACTION_SEND);
                shareIntent.putExtra(Intent.EXTRA_STREAM, uriToImage);
                shareIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                shareIntent.setType("image/*");
                // 遍历所有支持发送图片的应用。找到需要的应用
                ComponentName componentName = new ComponentName("com.tencent.mobileqq", "com.tencent.mobileqq.activity.JumpActivity");

                shareIntent.setComponent(componentName);
                // mContext.startActivity(shareIntent);
                mContext.startActivity(Intent.createChooser(shareIntent, "Share"));
            } catch (Exception e) {
//            ContextUtil.getInstance().showToastMsg("分享图片到**失败");
            }
        }
    }

之前有同学说在分享QQ和微信的时候,发现只要QQ或微信在打开的情况下,再调用分享只是打开了QQ和微信,却没有调用选择分享联系人的情况,这里,我要感觉一下@[努力搬砖]同学,他找出了原因。
解决办法如下:
 mActivity.startActivity(intent);//如果微信或者QQ已经唤醒或者打开,这样只能唤醒微信,不能分享 
请使用 mActivity.startActivity(Intent.createChooser(intent, "Share"));

QZone(QQ空间)

经过我反复试验,通过adb(方法:adb shell “dumpsys window | grep mCurrentFocus”)查找QQ中的空间发布说说界面是:cooperation.qzone.QzonePublishMoodProxyActivity,但始终歪能成功,在网上看到有人说是该界面没有对外开放,所以这里只能通过调用qq空间app打开发布界面进行分享内容!(强调:不是QQ内自带发布界面,是QQ空间单独的APP)。后期再研究下能否直接使用QQ内直接的界面。

/**
     * description : 分享到QQ空间
     * created at 2018/7/9 17:04
     *
     * @param photoPath 照片路径
     */
    public void shareImageToQQZone(String photoPath) {
        try {
            if (PlatformUtil.isInstalledSpecifiedApp(mActivity, PlatformUtil.PACKAGE_QZONG)) {
                File file = new File(photoPath);
                if (!file.exists()) {
                    String tip = "文件不存在";
                    Toast.makeText(mActivity, tip + " path = " + photoPath, Toast.LENGTH_LONG).show();
                    return;
                }

                Intent intent = new Intent();
                ComponentName componentName = new ComponentName(PlatformUtil.PACKAGE_QZONG, PlatformUtil.ACTIVITY_SHARE_QQ_ZONE);
                intent.setComponent(componentName);
                intent.setAction("android.intent.action.SEND");
                intent.setType("image/*");
                intent.putExtra(Intent.EXTRA_TEXT, "I'm so tired!!");
                if (file.isFile() && file.exists()) {
                    Uri uri;
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                        uri = FileProvider.getUriForFile(mContext, ShareToolUtil.AUTHORITY, file);
                    } else {
                        uri = Uri.fromFile(file);
                    }
                    intent.putExtra(Intent.EXTRA_STREAM, uri);
                }
                mActivity.startActivity(intent);
            } else {
                Toast.makeText(mActivity, "您需要安装QQ空间客户端", Toast.LENGTH_LONG).show();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

Wechat(微信好友)

/**
     * 直接分享图片到微信好友
     * @param context
     * @param picFile
     */
    public static void shareWechatFriend(Context context,String content ,File picFile){
        if (Platformutil.isInstallApp(mContext,PlatformUtil.PACKAGE_WE_CHAT)){
            Intent intent = new Intent();
            ComponentName cop = new ComponentName("com.tencent.mm","com.tencent.mm.ui.tools.ShareImgUI");
            intent.setComponent(cop);
            intent.setAction(Intent.ACTION_SEND);
            intent.setType("image/*");
            if (picFile != null) {
                if (picFile.isFile() && picFile.exists()) {
                    Uri uri;
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                        uri = FileProvider.getUriForFile(context, ShareToolUtil.AUTHORITY, picFile);
                    } else {
                        uri = Uri.fromFile(picFile);
                    }
                    intent.putExtra(Intent.EXTRA_STREAM, uri);
//                    intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, Uri);
                }
            }
//            intent.putExtra("Kdescription", !TextUtils.isEmpty(content) ? content : "");
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            // context.startActivity(intent);
            context.startActivity(Intent.createChooser(intent, "Share"));
        }else{
            Toast.makeText(context, "您需要安装微信客户端", Toast.LENGTH_LONG).show();
        }
    }

/**
     * 直接分享文本到微信好友
     *
     * @param context 上下文
     */
    public void shareWechatFriend(Context context, String content) {
        if (Platformutil.isInstallApp(mContext,PlatformUtil.PACKAGE_WE_CHAT)) {
            Intent intent = new Intent();
            ComponentName cop = new ComponentName("com.tencent.mm", "com.tencent.mm.ui.tools.ShareImgUI");
            intent.setComponent(cop);
            intent.setAction(Intent.ACTION_SEND);
            intent.putExtra("android.intent.extra.TEXT", content);
//            intent.putExtra("sms_body", content);
            intent.putExtra("Kdescription", !TextUtils.isEmpty(content) ? content : "");
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(intent);
        } else {
            Toast.makeText(context, "您需要安装微信客户端", Toast.LENGTH_LONG).show();
        }
    }

WechatMoment(微信朋友圈)分享:

(这段更新时间:19-05-23)可查看文章开头更新内容,这里说一下解决方法:在不能分享标题到朋友圈的时候,可以在点击分享按钮时,将需要分享的内容复制到剪贴板,并toast给用户到微信朋友圈发布界面粘帖。
   /**
     * 直接分享文本和图片到微信朋友圈
     * @param context
     * @param content
     */
    public static void shareWechatMoment(Context context, String content, File picFile) {
        if (PlatformUtil. isInstallApp(context,PlatformUtil.PACKAGE_WECHAT)) {
            Intent intent = new Intent();
            //分享精确到微信的页面,朋友圈页面,或者选择好友分享页面
            ComponentName comp = new ComponentName("com.tencent.mm", "com.tencent.mm.ui.tools.ShareToTimeLineUI");
            intent.setComponent(comp);
//            intent.setAction(Intent.ACTION_SEND_MULTIPLE);// 分享多张图片时使用
            intent.setAction(Intent.ACTION_SEND);
            intent.setType("image/*");
            //添加Uri图片地址--用于添加多张图片
            //ArrayList<Uri> imageUris = new ArrayList<>();
            //intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, imageUris);
            if (picFile != null) {
                if (picFile.isFile() && picFile.exists()) {
                    Uri uri;
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                        uri = FileProvider.getUriForFile(context, ShareToolUtil.AUTHORITY, picFile);
                    } else {
                        uri = Uri.fromFile(picFile);
                    }
                    intent.putExtra(Intent.EXTRA_STREAM, uri);
                }
            }
            // 微信现不能进行标题同时分享
            // intent.putExtra("Kdescription", !TextUtils.isEmpty(content) ? content : "");
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(intent);
        } else {
            Toast.makeText(context, "您需要安装微信客户端", Toast.LENGTH_LONG).show();
        }
    }
在上面微信好友和朋友圈分享的过程中遇到了这样一串代码:
 if (picFile.isFile() && picFile.exists()) {
     Uri uri;
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
         uri = FileProvider.getUriForFile(context, ShareToolUtil.AUTHORITY, picFile);
     } else {
         uri = Uri.fromFile(picFile);
     }
     intent.putExtra(Intent.EXTRA_STREAM, uri);
//   intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, Uri);
 }

上面这部分代码主要功能是判断了下文件是否存在,在android版本高过7.0(包括7.0版本)当前APP是不能直接向外部应用提供file开头的的文件路径,需要通过FileProvider转换一下。否则在7.0及以上版本手机将直接crash。
这里再提供下我这里具体的逻辑:

常量:ShareToolUtil.AUTHORITY --写在哪儿无所谓,只要能调用到
public static final String AUTHORITY = "com.gudd.demo.fileprovider";
// AndroidManifest需要加一个provider的标签,里面的authorities就是我们上面需要调用的一个常量
// 如果你有多个module的话也没关系,所有的module只要有一个地方写了这个就行,因为app打包以后所有的AndroidManifest文件将会合并到一起
<provider
            android:name="android.support.v4.content.FileProvider"
            // 再说一遍哦:这里的"com.gudd.demo"是自定义的,需要改成你们自己的名字,其实可以随便写啦。这里很重要,不能两个app使用相同的名字,否则~~嘿嘿,两个app是不能同时安装的!!
            android:authorities="com.gudd.demo.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths_screencapture" />
        </provider>

上面还有个资源文件:resource="@xml/file_paths_screencapture"


file_paths_screencapture.xml 该文件需要在AndroidManifest.xml中引用
//  上图是写这个文件要放的位置,随便哪个Module都没关系 
//  只要AndroidManifest里面能直接调用到就可以。但要记得写在xml里面。
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <root-path
        name="ext_sd_files"
        path="" />
    <files-path
        name="int_files"
        path="." />
    <external-path
        name="ext_files"
        path="" />
    <cache-path
        name="cache_files"
        path="" />
    <external-files-path
        name="ext_int_files"
        path="" />
</paths>
// 可能上面这串代码放到文件中会有些红色的波浪线,呵呵,但又有啥关系呢,能运行起来不就行了,哈哈
这里再提供一下我保存图片的一个方法:
public class ShareToolUtil {
    private static String sharePicName = "share_pic.jpg";
    private static String sharePicPath = Environment.getExternalStorageDirectory().getAbsolutePath()+ File.separator+"UmeBrowser"+File.separator+"sharepic"+File.separator;
    /**
     * 保存图片,并返回一个File类型的文件
     * 如今Android版本已经高达28了,但在使用该方法时,涉及到权限问题,本人在创建文件夹时遇到文件夹创建失败问题,遂将原因及解决方法记录如下:
问题:Android6.0以后,文件夹创建失败。也就是使用file.mkdirs方法.
解决方法:1.读写sdcard需要权限,但仅在manifest.xml里面添加是不够的,需要动态申请权限。2.可以将targetSdkVersion改为21或22或以下。
否则在分享过程中获取不到图片就会弹出“获取资源失败”这样的提示。
     */
    public static File saveSharePic(Context context, Bitmap bitmap){
        if (FileUtil.isSDcardExist()){
            File file = new File(sharePicPath);
            if (!file.exists()){
                file.mkdirs();
            }
            File filePic = new File(sharePicPath,sharePicName);
            if (filePic.exists()){
                filePic.delete();
            }
            try {
                FileOutputStream out = new FileOutputStream(filePic);
                if (bitmap == null) {
                    bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.share_homepage);
                }
                bitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
                try {
                    out.flush();
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return filePic;
        }
        return null;
    }
}

这就是我的方法,在分享微信朋友圈的时候需要注意一点,分享的图片要保存在微信可获取到的目录下,一定不能保存在/data/data/****这个内置目录中,否则将获取不到图片报“获取不到图片资源,.....”导致分享失败。

后面如果有时间我会再将新浪的分享给写进来。
今天是7月10日,距离这篇文章已经有段时间了,为了说到做到,我把新浪的也给分享出来,还是在回头看这篇文章的时候想到,原来忘记我说的新浪这回事儿了,哈哈。。。

新浪微博分享

新浪分享分为两部分,一部分指分享给好友,一部分分享到内容。看下面吧。

/**
     * description : 微博分享
     * created at 2018/7/10 13:58
     */
    public void shareToSinaFriends(Context context,boolean isFriends, String photoPath) {
        if (PlatformUtil.isInstalledSpecifiedApp(context, PlatformUtil.PACKAGE_SINA)) {

            File file = new File(photoPath);
            if (!file.exists()) {
                String tip = "文件不存在";
                Toast.makeText(context, tip + " path = " + photoPath, Toast.LENGTH_LONG).show();
                return;
            }

            Intent intent = new Intent(Intent.ACTION_SEND);
            // 使用以下两种type有一定的区别,"text/plain"分享给指定的粉丝或好友 ;"image/*"分享到微博内容
            if (isFriends) {
                intent.setType("text/plain");
            }else {
                intent.setType("image/*");// 分享文本|文本+图片|图片 到微博内容时使用
            }
            PackageManager packageManager = context.getPackageManager();
            List<ResolveInfo> matchs = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
            ResolveInfo resolveInfo = null;
            for (ResolveInfo each : matchs) {
                String pkgName = each.activityInfo.applicationInfo.packageName;
                if (PlatformUtil.PACKAGE_SINA.equals(pkgName)) {
                    resolveInfo = each;
                    break;
                }
            }
            // type = "image/*"--->com.sina.weibo.composerinde.ComposerDispatchActivity
            // type = "text/plain"--->com.sina.weibo.weiyou.share.WeiyouShareDispatcher
            intent.setClassName(PlatformUtil.PACKAGE_SINA, resolveInfo.activityInfo.name);// 这里在使用resolveInfo的时候需要做判空处理防止crash
            intent.putExtra(Intent.EXTRA_TEXT, "Test Text String !!");
            if (file.isFile() && file.exists()) {
                Uri uri;
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    uri = FileProvider.getUriForFile(mContext, ShareToolUtil.AUTHORITY, file);
                } else {
                    uri = Uri.fromFile(file);
                }
                intent.putExtra(Intent.EXTRA_STREAM, uri);
            }
            context.startActivity(intent);
        }else{
            Toast.makeText(mContext, "您需要安装sina客户端", Toast.LENGTH_LONG).show();
        }
    }

直接添加进入QQ群

之前有小伙伴问我如何实现QQ群直接加入功能,这里我简单给大家介绍一下,其实很简单,登录腾讯https://qun.qq.com/join.html就明白了。下面我贴下代码:

/**
* 该群目前为我个人新建测试群,无聊的小盆友也可以加入进来壮大我的号,哈哈
* 发起添加群流程。群号:Android学习交流(610194891) 的 key 为: CXaQmSGNixYtgpaRuUlxd0CwyMhQYkd_
* 调用 joinQQGroup(CXaQmSGNixYtgpaRuUlxd0CwyMhQYkd_) 即可发起手Q客户端申请加群 Android学习交流(610194891)
*
* @param key 由官网生成的key
* @return 返回true表示呼起手Q成功,返回fals表示呼起失败
*/
public boolean joinQQGroup(String key) {
    Intent intent = new Intent();
    intent.setData(Uri.parse("mqqopensdkapi://bizAgent/qm/qr?url=http%3A%2F%2Fqm.qq.com%2Fcgi-bin%2Fqm%2Fqr%3Ffrom%3Dapp%26p%3Dandroid%26k%3D" + key));
   // 此Flag可根据具体产品需要自定义,如设置,则在加群界面按返回,返回手Q主界面,不设置,按返回会返回到呼起产品界面    //intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
    try {
        startActivity(intent);
        return true;
    } catch (Exception e) {
        // 未安装手Q或安装的版本不支持
        return false;
    }
}

以上仅是个人工作中遇到的一些问题,记录下来方便以后查阅,如有优化方法请留言。

QQ、WECHAT在打开情况下分享时只能唤醒应用却不能调用分享联系人列表情况。解决办法如下:

调用开启分享界面 mActivity.startActivity(intent);//如果微信或者QQ已经唤醒或者打开,这样只能唤醒微信,不能分享 
请使用:mActivity.startActivity(Intent.createChooser(intent, "Share"));

推荐阅读更多精彩内容