package com.tsgame.tsgame_niuniu.util; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.net.Uri; import android.os.Build; import android.os.Handler; import android.os.Looper; import android.text.TextUtils; import android.util.Log; import android.widget.Toast; import java.io.File; import java.io.FileOutputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.UUID; /** * QQ分享工具类 - 无需SDK,使用Intent实现 */ public class QQIntentShareUtil { private static final String TAG = "QQIntentShareUtil"; // QQ可能的包名列表 private static final String QQ_PACKAGE_NAME = "com.tencent.mobileqq"; private static final String TIM_PACKAGE_NAME = "com.tencent.tim"; private static final String QQ_LITE_PACKAGE_NAME = "com.tencent.qqlite"; private static final String QQ_INTERNATIONAL_PACKAGE_NAME = "com.tencent.mobileqqi"; // 可能的QQ包名列表 private static final List QQ_PACKAGES = Arrays.asList( QQ_PACKAGE_NAME, // 标准QQ TIM_PACKAGE_NAME, // TIM QQ_LITE_PACKAGE_NAME, // QQ轻聊版 QQ_INTERNATIONAL_PACKAGE_NAME // 国际版QQ ); // QQ分享的Activity组件名称 private static final String QQ_SHARE_COMPONENT = "com.tencent.mobileqq.activity.JumpActivity"; private static final String QQ_TIM_SHARE_COMPONENT = "com.tencent.tim.activity.JumpActivity"; // QQ聊天的Activity组件名称 private static final String QQ_CHAT_COMPONENT = "com.tencent.mobileqq.activity.ChatActivity"; private static final String TIM_CHAT_COMPONENT = "com.tencent.tim.activity.ChatActivity"; // QQ临时会话的Activity组件名称 private static final String QQ_TEMP_CHAT_COMPONENT = "com.tencent.mobileqq.activity.TempSessionActivity"; private static final String TIM_TEMP_CHAT_COMPONENT = "com.tencent.tim.activity.TempSessionActivity"; // QQ空间分享的Activity组件名称 private static final String QZONE_COMPONENT = "com.tencent.mobileqq.activity.QzonePublishMoodActivity"; private static final String TIM_QZONE_COMPONENT = "com.tencent.tim.activity.QzonePublishMoodActivity"; private static QQIntentShareUtil instance; private final Context mContext; private QQShareCallback mCallback; // 缓存已安装的QQ包名 private String installedQQPackage = null; private QQIntentShareUtil(Context context) { this.mContext = context.getApplicationContext(); } public static QQIntentShareUtil getInstance(Context context) { if (instance == null && context != null) { instance = new QQIntentShareUtil(context); } return instance; } /** * 设置分享回调 * @param callback 分享回调 */ public void setShareCallback(QQShareCallback callback) { this.mCallback = callback; } /** * 检查QQ是否已安装 * @return 是否安装 */ public boolean isQQInstalled() { // 如果之前已找到包名,直接返回true if (installedQQPackage != null) { return true; } // 检查所有可能的QQ包名 PackageManager pm = mContext.getPackageManager(); for (String packageName : QQ_PACKAGES) { try { pm.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES); // 找到已安装的QQ,缓存包名 installedQQPackage = packageName; Log.d(TAG, "找到已安装的QQ: " + packageName); return true; } catch (PackageManager.NameNotFoundException e) { // 继续检查下一个包名 continue; } } Log.d(TAG, "未找到已安装的QQ应用"); return false; } /** * 获取已安装的QQ包名 * @return QQ包名,如果未安装则返回默认包名 */ private String getInstalledQQPackage() { if (installedQQPackage != null) { return installedQQPackage; } // 如果没有缓存,重新检测 isQQInstalled(); return installedQQPackage != null ? installedQQPackage : QQ_PACKAGE_NAME; } /** * 获取QQ分享的组件名称 */ private String getQQShareComponent() { String packageName = getInstalledQQPackage(); if (TIM_PACKAGE_NAME.equals(packageName)) { return QQ_TIM_SHARE_COMPONENT; } return QQ_SHARE_COMPONENT; } /** * 获取QQ聊天的组件名称 */ private String getQQChatComponent() { String packageName = getInstalledQQPackage(); if (TIM_PACKAGE_NAME.equals(packageName)) { return TIM_CHAT_COMPONENT; } return QQ_CHAT_COMPONENT; } /** * 获取QQ临时会话的组件名称 */ private String getQQTempChatComponent() { String packageName = getInstalledQQPackage(); if (TIM_PACKAGE_NAME.equals(packageName)) { return TIM_TEMP_CHAT_COMPONENT; } return QQ_TEMP_CHAT_COMPONENT; } /** * 获取QQ空间分享的组件名称 */ private String getQZoneShareComponent() { String packageName = getInstalledQQPackage(); if (TIM_PACKAGE_NAME.equals(packageName)) { return TIM_QZONE_COMPONENT; } return QZONE_COMPONENT; } /** * 分享纯文本到QQ好友 * @param activity 活动 * @param text 要分享的文本 */ public void shareTextToQQ(Activity activity, String text) { if (!isQQInstalled()) { handleNotInstalled(activity); return; } try { // 1. 将文本复制到剪贴板 copyToClipboard(activity, text); // Toast.makeText(activity, "内容已复制到剪贴板,请选择联系人后粘贴发送", Toast.LENGTH_LONG).show(); // 2. 使用QQ的特定组件启动联系人选择界面 String packageName = getInstalledQQPackage(); boolean launched = false; // // 新增方法: 使用QQ最新的联系人选择器组件 // if (!launched) { // try { // Intent intent = new Intent(); // // 使用QQ联系人选择Activity (QQ8.x及以上版本支持) // ComponentName comp = new ComponentName(packageName, "com.tencent.mobileqq.activity.FriendProfileCardActivity"); // intent.setComponent(comp); // // 添加特定参数 // intent.putExtra("fling_action_key", 2); // 2表示选择联系人 // intent.putExtra("preAct", "ContactsActivity"); // intent.putExtra("need_update_friend_list", true); // intent.putExtra("isFromShare", true); // intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // activity.startActivity(intent); // launched = true; // Log.d(TAG, "成功使用FriendProfileCardActivity启动QQ联系人选择器"); // } catch (Exception e) { // Log.e(TAG, "使用FriendProfileCardActivity启动QQ联系人选择器失败: " + e.getMessage()); // } // } // 方法1: 使用QQ的联系人选择器组件 if (!launched) { try { Intent intent = new Intent(); // 使用专门的联系人选择Activity ComponentName comp = new ComponentName(packageName, "com.tencent.mobileqq.activity.contacts.SortContactsListActivity"); intent.setComponent(comp); // 添加特定参数,提示QQ这是一个分享操作 intent.putExtra("key_operation_type", 5); // 5表示分享操作类型 intent.putExtra("key_is_friend_chooser", 1); intent.putExtra("key_source_from", 12); intent.putExtra("isFromShare", true); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); activity.startActivity(intent); launched = true; Log.d(TAG, "成功使用联系人选择器组件启动QQ"); } catch (Exception e) { Log.e(TAG, "使用联系人选择器组件启动QQ失败: " + e.getMessage()); } } // 方法2: 使用QQ的跳转组件并携带分享标识 if (!launched) { try { Intent intent = new Intent(); ComponentName comp = new ComponentName(packageName, getQQShareComponent()); intent.setComponent(comp); // 添加分享参数 intent.setAction(Intent.ACTION_SEND); intent.setType("text/plain"); intent.putExtra(Intent.EXTRA_TEXT, text); // 添加特定参数,强制打开联系人选择器 intent.putExtra("pkg_name", activity.getPackageName()); intent.putExtra("from_scene", 10); // 10表示APP分享 intent.putExtra("req_type", 1); // 1表示选择好友 intent.putExtra("to_scene", 2); // 2表示聊天窗口 intent.putExtra("isFromShare", true); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); activity.startActivity(intent); launched = true; Log.d(TAG, "成功使用分享组件启动QQ"); } catch (Exception e) { Log.e(TAG, "使用分享组件启动QQ失败: " + e.getMessage()); } } // 方法3: 使用QQ的会话Activity if (!launched) { try { Intent intent = new Intent(); ComponentName comp = new ComponentName(packageName, "com.tencent.mobileqq.activity.FriendlistActivity"); intent.setComponent(comp); intent.putExtra("isFromShare", true); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); activity.startActivity(intent); launched = true; Log.d(TAG, "成功使用好友列表Activity启动QQ"); } catch (Exception e) { Log.e(TAG, "使用好友列表Activity启动QQ失败: " + e.getMessage()); } } // 方法4: 使用通常的标准聊天组件 if (!launched) { try { Intent intent = new Intent(); ComponentName comp = new ComponentName(packageName, getQQChatComponent()); intent.setComponent(comp); intent.putExtra("uinname", ""); intent.putExtra("uintype", 0); intent.putExtra("isFromShare", true); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); activity.startActivity(intent); launched = true; Log.d(TAG, "成功使用聊天组件启动QQ"); } catch (Exception e) { Log.e(TAG, "使用聊天组件启动QQ失败: " + e.getMessage()); } } // 如果以上方法都失败,回退到标准启动方法 if (!launched) { try { Intent launchIntent = activity.getPackageManager().getLaunchIntentForPackage(packageName); if (launchIntent != null) { launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); activity.startActivity(launchIntent); launched = true; Log.d(TAG, "成功使用标准方式启动QQ"); } } catch (Exception e) { Log.e(TAG, "标准方式启动QQ失败: " + e.getMessage()); } } // 如果以上方法都失败,尝试系统分享 if (!launched) { Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("text/plain"); intent.putExtra(Intent.EXTRA_TEXT, text); Intent chooser = Intent.createChooser(intent, "分享到QQ"); activity.startActivity(chooser); Toast.makeText(activity, "请从列表中选择QQ", Toast.LENGTH_SHORT).show(); } else { // Toast.makeText(activity, "请选择联系人并粘贴内容", Toast.LENGTH_LONG).show(); } // 假设分享过程启动成功 if (mCallback != null) { new Handler(Looper.getMainLooper()).postDelayed(() -> { mCallback.onSuccess(); }, 1000); } } catch (Exception e) { Log.e(TAG, "分享文本到QQ失败: " + e.getMessage(), e); handleShareException(activity, e); } } /** * 分享纯文本到QQ空间 * @param activity 活动 * @param text 要分享的文本 */ public void shareTextToQZone(Activity activity, String text) { if (!isQQInstalled()) { handleNotInstalled(activity); return; } try { String packageName = getInstalledQQPackage(); Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("text/plain"); intent.putExtra(Intent.EXTRA_TEXT, text); // 使用组件名称直接跳转到QQ空间分享界面 ComponentName comp = new ComponentName(packageName, getQZoneShareComponent()); intent.setComponent(comp); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); activity.startActivity(intent); Toast.makeText(activity, "正在分享到QQ空间", Toast.LENGTH_SHORT).show(); // 假设分享成功 if (mCallback != null) { new Handler(Looper.getMainLooper()).postDelayed(() -> { mCallback.onSuccess(); }, 1000); } } catch (Exception e) { Log.e(TAG, "分享文本到QQ空间失败: " + e.getMessage(), e); // 尝试使用通用分享 try { Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("text/plain"); intent.putExtra(Intent.EXTRA_TEXT, text); Intent chooser = Intent.createChooser(intent, "分享到QQ空间"); activity.startActivity(chooser); Toast.makeText(activity, "请从列表中选择QQ", Toast.LENGTH_SHORT).show(); if (mCallback != null) { new Handler(Looper.getMainLooper()).postDelayed(() -> { mCallback.onSuccess(); }, 1000); } } catch (Exception ex) { handleShareException(activity, ex); } } } /** * 分享图片到QQ * @param activity 活动 * @param localImagePath 本地图片路径 */ public void shareImageToQQ(Activity activity, String localImagePath) { if (!isQQInstalled()) { handleNotInstalled(activity); return; } File imageFile = new File(localImagePath); if (!imageFile.exists()) { Toast.makeText(activity, "分享图片不存在", Toast.LENGTH_SHORT).show(); if (mCallback != null) { mCallback.onError(-2, "图片文件不存在"); } return; } try { String packageName = getInstalledQQPackage(); // 创建分享Intent Intent shareIntent = new Intent(Intent.ACTION_SEND); shareIntent.setType("image/*"); // 设置组件名称 ComponentName comp = new ComponentName(packageName, getQQShareComponent()); shareIntent.setComponent(comp); // 根据Android版本使用不同的Uri方式 Uri imageUri; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // Android 7.0及以上使用FileProvider imageUri = FileProviderUtil.getUriForFile(activity, imageFile); shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); } else { // Android 7.0以下直接使用文件Uri imageUri = Uri.fromFile(imageFile); } shareIntent.putExtra(Intent.EXTRA_STREAM, imageUri); shareIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { activity.startActivity(shareIntent); Log.d(TAG, "已发送分享图片Intent到QQ"); // 延迟回调成功 if (mCallback != null) { new Handler(Looper.getMainLooper()).postDelayed(() -> { mCallback.onSuccess(); }, 1000); } } catch (android.content.ActivityNotFoundException e) { Log.e(TAG, "直接分享到QQ失败,尝试使用选择器: " + e.getMessage()); // 如果直接分享失败,使用选择器 Intent chooserIntent = Intent.createChooser(shareIntent.setComponent(null), "分享到QQ"); activity.startActivity(chooserIntent); Toast.makeText(activity, "请从列表中选择QQ", Toast.LENGTH_SHORT).show(); // 假设分享成功 if (mCallback != null) { new Handler(Looper.getMainLooper()).postDelayed(() -> { mCallback.onSuccess(); }, 1000); } } } catch (Exception e) { Log.e(TAG, "分享图片到QQ失败: " + e.getMessage(), e); handleShareException(activity, e); } } /** * 分享图片到QQ空间 * @param activity 活动 * @param localImagePath 本地图片路径 */ public void shareImageToQZone(Activity activity, String localImagePath) { if (!isQQInstalled()) { handleNotInstalled(activity); return; } File imageFile = new File(localImagePath); if (!imageFile.exists()) { Toast.makeText(activity, "分享图片不存在", Toast.LENGTH_SHORT).show(); if (mCallback != null) { mCallback.onError(-2, "图片文件不存在"); } return; } try { String packageName = getInstalledQQPackage(); // 创建分享Intent Intent shareIntent = new Intent(Intent.ACTION_SEND); shareIntent.setType("image/*"); // 设置组件名称 ComponentName comp = new ComponentName(packageName, getQZoneShareComponent()); shareIntent.setComponent(comp); // 根据Android版本使用不同的Uri方式 Uri imageUri; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // Android 7.0及以上使用FileProvider imageUri = FileProviderUtil.getUriForFile(activity, imageFile); shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); } else { // Android 7.0以下直接使用文件Uri imageUri = Uri.fromFile(imageFile); } shareIntent.putExtra(Intent.EXTRA_STREAM, imageUri); shareIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { activity.startActivity(shareIntent); Log.d(TAG, "已发送分享图片Intent到QQ空间"); // 延迟回调成功 if (mCallback != null) { new Handler(Looper.getMainLooper()).postDelayed(() -> { mCallback.onSuccess(); }, 1000); } } catch (android.content.ActivityNotFoundException e) { Log.e(TAG, "直接分享到QQ空间失败,尝试使用选择器: " + e.getMessage()); // 如果直接分享失败,使用选择器 Intent chooserIntent = Intent.createChooser(shareIntent.setComponent(null), "分享到QQ空间"); activity.startActivity(chooserIntent); Toast.makeText(activity, "请从列表中选择QQ", Toast.LENGTH_SHORT).show(); // 假设分享成功 if (mCallback != null) { new Handler(Looper.getMainLooper()).postDelayed(() -> { mCallback.onSuccess(); }, 1000); } } } catch (Exception e) { Log.e(TAG, "分享图片到QQ空间失败: " + e.getMessage(), e); handleShareException(activity, e); } } /** * 分享Bitmap到QQ * @param activity 活动 * @param bitmap 位图 * @param isQzone 是否分享到QQ空间 */ public void shareBitmapToQQ(Activity activity, Bitmap bitmap, boolean isQzone) { if (bitmap == null) { Toast.makeText(activity, "分享图片为空", Toast.LENGTH_SHORT).show(); if (mCallback != null) { mCallback.onError(-1, "分享图片为空"); } return; } try { File cacheDir = activity.getExternalCacheDir(); if (cacheDir == null) { cacheDir = activity.getCacheDir(); } File imageFile = new File(cacheDir, "qq_share_" + UUID.randomUUID().toString() + ".jpg"); FileOutputStream fos = new FileOutputStream(imageFile); bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos); fos.flush(); fos.close(); // 保存成功,分享图片 if (isQzone) { shareImageToQZone(activity, imageFile.getAbsolutePath()); } else { shareImageToQQ(activity, imageFile.getAbsolutePath()); } } catch (Exception e) { Toast.makeText(activity, "保存图片失败: " + e.getMessage(), Toast.LENGTH_SHORT).show(); if (mCallback != null) { mCallback.onError(-2, "保存图片失败: " + e.getMessage()); } } } /** * 分享多张图片到QQ(群发) * @param activity 活动 * @param imagePaths 图片路径列表 * @param isQzone 是否分享到QQ空间 */ public void shareImagesToQQ(Activity activity, ArrayList imagePaths, boolean isQzone) { if (!isQQInstalled()) { handleNotInstalled(activity); return; } if (imagePaths == null || imagePaths.isEmpty()) { Toast.makeText(activity, "分享图片为空", Toast.LENGTH_SHORT).show(); if (mCallback != null) { mCallback.onError(-1, "分享图片为空"); } return; } try { ArrayList imageUris = new ArrayList<>(); for (String path : imagePaths) { File file = new File(path); if (file.exists()) { // 根据Android版本使用不同的Uri方式 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // Android 7.0及以上使用FileProvider Uri fileUri = FileProviderUtil.getUriForFile(activity, file); imageUris.add(fileUri); } else { // Android 7.0以下直接使用文件Uri imageUris.add(Uri.fromFile(file)); } } } if (imageUris.isEmpty()) { Toast.makeText(activity, "没有有效图片可分享", Toast.LENGTH_SHORT).show(); if (mCallback != null) { mCallback.onError(-1, "没有有效图片可分享"); } return; } Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE); // 获取已安装的QQ包名 String packageName = getInstalledQQPackage(); intent.setPackage(packageName); intent.setType("image/*"); intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, imageUris); // 设置组件名称 if (isQzone) { ComponentName comp = new ComponentName(packageName, getQZoneShareComponent()); intent.setComponent(comp); } else { ComponentName comp = new ComponentName(packageName, getQQShareComponent()); intent.setComponent(comp); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); } intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { activity.startActivity(intent); Log.d(TAG, "已发送多图分享Intent到QQ"); // 延迟回调成功 if (mCallback != null) { new Handler(Looper.getMainLooper()).postDelayed(() -> { mCallback.onSuccess(); }, 1000); } } catch (Exception e) { // 如果直接分享失败,使用系统分享选择器 Log.d(TAG, "多图直接分享失败,使用系统分享: " + e.getMessage()); Intent chooser = Intent.createChooser(intent.setComponent(null), isQzone ? "分享到QQ空间" : "分享到QQ"); activity.startActivity(chooser); Toast.makeText(activity, "请从列表中选择QQ", Toast.LENGTH_SHORT).show(); // 假设分享成功 if (mCallback != null) { new Handler(Looper.getMainLooper()).postDelayed(() -> { mCallback.onSuccess(); }, 1000); } } } catch (Exception e) { handleShareException(activity, e); } } /** * 分享网页链接到QQ * @param activity 活动 * @param title 标题 * @param description 描述 * @param webUrl 网页链接 * @param imageUrl 图片链接(可选) * @param isQzone 是否分享到QQ空间 */ public void shareWebPageToQQ(Activity activity, String title, String description, String webUrl, String imageUrl, boolean isQzone) { if (!isQQInstalled()) { handleNotInstalled(activity); return; } try { // QQ支持直接分享网页链接,但实际上QQ会解析文本内容来查找URL StringBuilder sb = new StringBuilder(); if (!TextUtils.isEmpty(title)) { sb.append(title).append("\n\n"); } if (!TextUtils.isEmpty(description)) { sb.append(description).append("\n\n"); } String text = sb.toString().trim(); if (isQzone) { shareTextToQZone(activity, text); } else { shareTextToQQ(activity, text); } } catch (Exception e) { handleShareException(activity, e); } } /** * 处理未安装QQ的情况 */ private void handleNotInstalled(Activity activity) { Toast.makeText(activity, "请先安装QQ客户端", Toast.LENGTH_SHORT).show(); if (mCallback != null) { mCallback.onError(-1, "未安装QQ客户端"); } } /** * 处理分享异常 */ private void handleShareException(Activity activity, Exception e) { Toast.makeText(activity, "分享失败: " + e.getMessage(), Toast.LENGTH_SHORT).show(); if (mCallback != null) { mCallback.onError(-3, "分享失败: " + e.getMessage()); } } /** * 兼容性复制文本到剪贴板 * 支持API 9及以上版本 * @param context 上下文 * @param text 要复制的文本 */ private void copyToClipboard(Context context, String text) { try { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { // API 11及以上使用ClipboardManager android.content.ClipboardManager clipboardManager = (android.content.ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); android.content.ClipData clipData = android.content.ClipData.newPlainText("分享内容", text); clipboardManager.setPrimaryClip(clipData); } else { // API 11以下使用旧版的android.text.ClipboardManager android.text.ClipboardManager clipboardManager = (android.text.ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); clipboardManager.setText(text); } } catch (Exception e) { Log.e(TAG, "复制到剪贴板失败: " + e.getMessage(), e); } } /** * QQ分享回调接口 */ public interface QQShareCallback { /** * 分享成功 */ void onSuccess(); /** * 分享失败 * @param code 错误码 * @param msg 错误信息 */ void onError(int code, String msg); /** * 分享取消 */ void onCancel(); } }