Files
youle_app_ios/msext/Class/Utils/QQShareManager.m
joywayer 2296c65974 feat: 重构分享功能 - 将各平台分享逻辑整理到对应Manager中
- 新增 WechatShareManager:封装微信分享逻辑,支持ShareContent对象
- 增强 DouyinShareManager:新增ShareContent支持和分享引导功能
- 优化 QQShareManager:支持截图/纯文本分享类型自动识别
- 重构 SharePanel:简化为UI调度层,移除具体分享实现
- 实现职责分离:各Manager专注自己的平台分享逻辑
- 提升可维护性:修改某平台不影响其他平台
- 增强可扩展性:新增分享平台更容易实现
2025-06-17 19:55:44 +08:00

1474 lines
57 KiB
Objective-C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//
// QQShareManager.m
// msext
//
// Created on 2025/06/15.
// Copyright © 2025年. All rights reserved.
//
#import "QQShareManager.h"
#import "FuncPublic.h" // 用于截图功能
// QQ URL Schemes
#define kQQScheme @"mqqapi://"
#define kQQShareScheme @"mqqapi://share/"
#define kQQFriendScheme @"mqqapi://share/to_fri?"
#define kQQZoneScheme @"mqqapi://share/to_qzone?"
#define kQQUniversalScheme @"mqq://share/to_fri?" // 通用分享scheme无需AppID验证
// QQ 分享必需的参数
#define kQQAppName @"进贤聚友棋牌" // 应用名称与Info.plist中的CFBundleDisplayName和CFBundleName保持一致
#define kQQCallbackScheme @"msext" // 回调scheme
#define kQQAppID @"102793577" // 您当前的AppID
#define kQQFallbackAppID @"100312206" // 腾讯官方测试AppID通常可用
// QQ 应用回调的处理
static void(^QQShareCompletion)(BOOL) = nil;
@implementation QQShareManager
#pragma mark - Public Methods
+ (BOOL)isQQInstalled {
return [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:kQQScheme]];
}
+ (BOOL)validateQQAppIDConfiguration {
NSLog(@"🔍 开始验证QQ AppID配置...");
NSLog(@"🔍 当前AppID值%@", kQQAppID);
NSLog(@"🔍 AppID长度%lu", (unsigned long)[kQQAppID length]);
// 检查AppID是否配置
if (!kQQAppID || [kQQAppID isEqualToString:@"YOUR_QQ_APPID"]) {
NSLog(@"❌ QQ AppID 未配置!请在 QQShareManager.m 中设置正确的 kQQAppID");
return NO;
}
// 检查AppID格式应该是纯数字长度在8-10位之间
NSCharacterSet *nonDigits = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
if ([kQQAppID rangeOfCharacterFromSet:nonDigits].location != NSNotFound) {
NSLog(@"❌ QQ AppID 格式错误AppID应该是纯数字当前%@", kQQAppID);
return NO;
}
// 检查长度现代QQ AppID通常是8-10位数字
if (kQQAppID.length < 8 || kQQAppID.length > 10) {
NSLog(@"❌ QQ AppID 长度错误AppID应该是8-10位数字当前长度%luAppID%@", (unsigned long)kQQAppID.length, kQQAppID);
return NO;
}
NSLog(@"✅ QQ AppID 配置正确:%@", kQQAppID);
NSLog(@"⚠️ 重要提示如果出现900101错误请确认");
NSLog(@"⚠️ 1. AppID是否已在QQ开放平台审核通过");
NSLog(@"⚠️ 2. Bundle ID是否与申请时一致");
NSLog(@"⚠️ 3. 应用是否已上线或处于测试白名单");
return YES;
}
+ (NSString *)getCurrentQQAppID {
if ([self validateQQAppIDConfiguration]) {
return kQQAppID;
}
return nil;
}
+ (void)shareToQQFriend:(QQShareType)type
title:(NSString *)title
description:(NSString *)description
thumbImage:(UIImage *)thumbImage
url:(NSString *)url
image:(UIImage *)image
completion:(void (^)(BOOL))completion {
// 检查QQ是否已安装
if (![self isQQInstalled]) {
if (completion) {
completion(NO);
}
[self showAppNotInstalledAlert:@"QQ"];
return;
}
// 验证AppID配置解决9000101错误的关键
if (![self validateQQAppIDConfiguration]) {
if (completion) {
completion(NO);
}
[self showAppIDConfigurationErrorAlert];
return;
}
// 保存回调
QQShareCompletion = completion;
// 构建URL参数 - 使用QQ官方标准格式解决900101错误
NSMutableString *urlString = [NSMutableString stringWithString:kQQFriendScheme];
// QQ官方要求的标准参数顺序和格式
[urlString appendString:@"version=1"];
[urlString appendString:@"&cflag=0"];
[urlString appendString:@"&src_type=app"];
// 尝试使用QQ最新推荐的参数格式
[urlString appendFormat:@"&thirdAppDisplayName=%@", [self encodeString:kQQAppName]];
[urlString appendFormat:@"&app_id=%@", kQQAppID];
[urlString appendFormat:@"&sdkv=2.9.0"];
[urlString appendFormat:@"&sdkp=i"];
// 回调相关参数
[urlString appendString:@"&callback_type=scheme"];
[urlString appendFormat:@"&callback_name=%@", [self encodeString:kQQCallbackScheme]];
// 获取Bundle ID用于验证
NSString *bundleId = [[NSBundle mainBundle] bundleIdentifier];
// 添加详细调试日志
NSLog(@"🔍 ======== QQ分享参数详情 ========");
NSLog(@"🔍 AppID: %@", kQQAppID);
NSLog(@"🔍 Bundle ID: %@", bundleId);
NSLog(@"🔍 AppName: %@", kQQAppName);
NSLog(@"🔍 CallbackScheme: %@", kQQCallbackScheme);
NSLog(@"🔍 QQ Friend Scheme: %@", kQQFriendScheme);
// 根据分享类型设置不同的参数
switch (type) {
case QQShareTypeText:
[urlString appendString:@"&req_type=0"];
if (title && title.length > 0) {
[urlString appendFormat:@"&title=%@", [self encodeString:title]];
}
if (description && description.length > 0) {
[urlString appendFormat:@"&description=%@", [self encodeString:description]];
}
break;
case QQShareTypeImage:
if (image) {
// 将图片保存到本地临时目录
NSString *imagePath = [self saveImageToTempDirectory:image];
[urlString appendString:@"&req_type=2"];
[urlString appendFormat:@"&image_url=%@", [self encodeString:[@"file://" stringByAppendingString:imagePath]]];
if (title && title.length > 0) {
[urlString appendFormat:@"&title=%@", [self encodeString:title]];
}
if (description && description.length > 0) {
[urlString appendFormat:@"&description=%@", [self encodeString:description]];
}
} else {
if (completion) {
completion(NO);
}
return;
}
break;
case QQShareTypeNews:
[urlString appendString:@"&req_type=1"];
if (title && title.length > 0) {
[urlString appendFormat:@"&title=%@", [self encodeString:title]];
}
if (description && description.length > 0) {
[urlString appendFormat:@"&description=%@", [self encodeString:description]];
}
if (url && url.length > 0) {
[urlString appendFormat:@"&url=%@", [self encodeString:url]];
}
// 将缩略图保存到本地
if (thumbImage) {
NSString *thumbPath = [self saveImageToTempDirectory:thumbImage];
[urlString appendFormat:@"&previewimageUrl=%@", [self encodeString:[@"file://" stringByAppendingString:thumbPath]]];
}
break;
case QQShareTypeAudio:
[urlString appendString:@"&req_type=3"];
if (title && title.length > 0) {
[urlString appendFormat:@"&title=%@", [self encodeString:title]];
}
if (description && description.length > 0) {
[urlString appendFormat:@"&description=%@", [self encodeString:description]];
}
if (url && url.length > 0) {
[urlString appendFormat:@"&url=%@", [self encodeString:url]];
}
if (thumbImage) {
NSString *thumbPath = [self saveImageToTempDirectory:thumbImage];
[urlString appendFormat:@"&previewimageUrl=%@", [self encodeString:[@"file://" stringByAppendingString:thumbPath]]];
}
break;
case QQShareTypeVideo:
[urlString appendString:@"&req_type=4"];
if (title && title.length > 0) {
[urlString appendFormat:@"&title=%@", [self encodeString:title]];
}
if (description && description.length > 0) {
[urlString appendFormat:@"&description=%@", [self encodeString:description]];
}
if (url && url.length > 0) {
[urlString appendFormat:@"&url=%@", [self encodeString:url]];
}
if (thumbImage) {
NSString *thumbPath = [self saveImageToTempDirectory:thumbImage];
[urlString appendFormat:@"&previewimageUrl=%@", [self encodeString:[@"file://" stringByAppendingString:thumbPath]]];
}
break;
}
// 详细的URL调试日志
NSLog(@"🔍 ======== 完整QQ分享URL ========");
NSLog(@"🔍 URL: %@", urlString);
NSLog(@"🔍 URL长度: %lu", (unsigned long)[urlString length]);
// 检查关键参数是否正确
if ([urlString containsString:[NSString stringWithFormat:@"app_id=%@", kQQAppID]]) {
NSLog(@"✅ AppID参数已包含");
} else {
NSLog(@"❌ AppID参数缺失");
}
NSURL *qqURL = [NSURL URLWithString:urlString];
if ([[UIApplication sharedApplication] canOpenURL:qqURL]) {
if (@available(iOS 10.0, *)) {
[[UIApplication sharedApplication] openURL:qqURL options:@{} completionHandler:^(BOOL success) {
// 这里不调用completion等待QQ返回再调用
NSLog(@"QQ分享调用结果: %@", success ? @"成功" : @"失败");
}];
} else {
[[UIApplication sharedApplication] openURL:qqURL];
}
} else {
if (completion) {
completion(NO);
}
}
}
+ (void)shareToQZone:(QQShareType)type
title:(NSString *)title
description:(NSString *)description
thumbImage:(UIImage *)thumbImage
url:(NSString *)url
images:(NSArray<UIImage *> *)images
completion:(void (^)(BOOL))completion {
// 检查QQ是否已安装
if (![self isQQInstalled]) {
if (completion) {
completion(NO);
}
[self showAppNotInstalledAlert:@"QQ"];
return;
}
// 验证AppID配置解决9000101错误的关键
if (![self validateQQAppIDConfiguration]) {
if (completion) {
completion(NO);
}
[self showAppIDConfigurationErrorAlert];
return;
}
// 保存回调
QQShareCompletion = completion;
// 构建URL参数 - 修复QQ空间分享格式
NSMutableString *urlString = [NSMutableString stringWithString:kQQZoneScheme];
// 基础必需参数严格按照QQ要求的格式和顺序
[urlString appendString:@"version=1"];
[urlString appendString:@"&cflag=0"];
[urlString appendFormat:@"&app_id=%@", kQQAppID]; // AppID必须在前面位置
[urlString appendString:@"&src_type=app"];
[urlString appendString:@"&sdkv=2.9.0"];
[urlString appendString:@"&sdkp=i"];
// 应用信息参数 - AppID是解决9000101错误的关键参数
[urlString appendFormat:@"&appid=%@", kQQAppID]; // QQ AppID - 必需参数
[urlString appendFormat:@"&app_name=%@", [self encodeString:kQQAppName]];
[urlString appendString:@"&callback_type=scheme"];
[urlString appendFormat:@"&callback_name=%@", [self encodeString:kQQCallbackScheme]];
// 添加内容参数
if (title && title.length > 0) {
[urlString appendFormat:@"&title=%@", [self encodeString:title]];
}
if (description && description.length > 0) {
[urlString appendFormat:@"&description=%@", [self encodeString:description]];
}
if (url && url.length > 0) {
[urlString appendFormat:@"&url=%@", [self encodeString:url]];
}
// 处理图片
if (images && images.count > 0) {
NSMutableArray *imagePaths = [NSMutableArray array];
for (UIImage *image in images) {
NSString *imagePath = [self saveImageToTempDirectory:image];
[imagePaths addObject:[@"file://" stringByAppendingString:imagePath]];
}
if (imagePaths.count > 0) {
[urlString appendFormat:@"&imageUrl=%@", [self encodeString:[imagePaths componentsJoinedByString:@","]]];
}
} else if (thumbImage) {
NSString *thumbPath = [self saveImageToTempDirectory:thumbImage];
[urlString appendFormat:@"&previewimageUrl=%@", [self encodeString:[@"file://" stringByAppendingString:thumbPath]]];
}
// 设置分享类型
switch (type) {
case QQShareTypeText:
[urlString appendString:@"&req_type=0"];
break;
case QQShareTypeImage:
[urlString appendString:@"&req_type=2"];
break;
case QQShareTypeNews:
[urlString appendString:@"&req_type=1"];
break;
case QQShareTypeAudio:
[urlString appendString:@"&req_type=3"];
break;
case QQShareTypeVideo:
[urlString appendString:@"&req_type=4"];
break;
}
// 打开URL
NSLog(@"QQ空间分享URL: %@", urlString);
NSURL *qzoneURL = [NSURL URLWithString:urlString];
if ([[UIApplication sharedApplication] canOpenURL:qzoneURL]) {
if (@available(iOS 10.0, *)) {
[[UIApplication sharedApplication] openURL:qzoneURL options:@{} completionHandler:^(BOOL success) {
// 这里不调用completion等待QQ返回再调用
}];
} else {
[[UIApplication sharedApplication] openURL:qzoneURL];
}
} else {
if (completion) {
completion(NO);
}
}
}
+ (BOOL)handleOpenURL:(NSURL *)url {
// 判断是否是QQ返回的URL
NSString *urlString = [url absoluteString];
NSLog(@"QQ分享回调URL: %@", urlString);
if ([urlString hasPrefix:@"msext://"]) {
// 解析返回的参数
NSString *errorDescription = [self getUrlParam:urlString paramName:@"error_description"];
NSString *error = [self getUrlParam:urlString paramName:@"error"];
BOOL success = YES;
if (error && ![error isEqualToString:@"0"]) {
success = NO;
NSLog(@"QQ分享失败: error=%@, description=%@", error, errorDescription);
} else {
NSLog(@"QQ分享成功");
}
// 执行回调
if (QQShareCompletion) {
QQShareCompletion(success);
QQShareCompletion = nil;
}
return YES;
}
return NO;
}
#pragma mark - 简化版QQ分享方法解决900101错误
/**
* 简化版QQ分享方法使用最基础的参数避免900101错误
*/
+ (void)simpleShareToQQFriend:(NSString *)title
description:(NSString *)description
url:(NSString *)url
completion:(void(^)(BOOL success))completion {
if (![self isQQInstalled]) {
if (completion) {
completion(NO);
}
[self showAppNotInstalledAlert:@"QQ"];
return;
}
// 保存回调
QQShareCompletion = completion;
// 使用最简单的URL格式避免复杂参数导致的900101错误
NSMutableString *urlString = [NSMutableString stringWithString:@"mqqapi://share/to_fri?"];
// 最基础的必需参数
[urlString appendString:@"version=1"];
[urlString appendString:@"&cflag=0"];
// 分享类型 - 根据是否有URL决定
if (url && url.length > 0) {
[urlString appendString:@"&req_type=1"]; // 网页分享
[urlString appendFormat:@"&url=%@", [self encodeString:url]];
} else {
[urlString appendString:@"&req_type=0"]; // 文本分享
}
// 内容参数
if (title && title.length > 0) {
[urlString appendFormat:@"&title=%@", [self encodeString:title]];
}
if (description && description.length > 0) {
[urlString appendFormat:@"&description=%@", [self encodeString:description]];
}
// 打开URL
NSLog(@"简化QQ分享URL: %@", urlString);
NSURL *qqURL = [NSURL URLWithString:urlString];
if ([[UIApplication sharedApplication] canOpenURL:qqURL]) {
if (@available(iOS 10.0, *)) {
[[UIApplication sharedApplication] openURL:qqURL options:@{} completionHandler:^(BOOL success) {
NSLog(@"简化QQ分享调用结果: %@", success ? @"成功" : @"失败");
}];
} else {
[[UIApplication sharedApplication] openURL:qqURL];
}
} else {
if (completion) {
completion(NO);
}
}
}
+ (void)forceOpenQQSessionSelector:(void(^)(BOOL success))completion {
NSLog(@"尝试强制弹出QQ会话选择列表...");
// 检查QQ是否安装
if (![self isQQInstalled]) {
NSLog(@"QQ未安装");
if (completion) completion(NO);
return;
}
// 尝试的URL方案按优先级排序
NSArray *urlTemplates = @[
// 方案1: 使用好友分享接口
@"mqqopensdkfriend://share?src_type=internal&version=1&app_name=%@&title=%@",
// 方案2: 直接打开聊天选择界面
@"mqq://im/chat?chat_type=select",
// 方案3: 打开好友列表
@"mqq://contact/friend_list",
// 方案4: 打开最近会话
@"mqq://im/recent",
// 方案5: 使用分享到好友
@"mqqapi://share/to_fri?file_type=text&file_data=%@&app_name=%@",
// 方案6: 简化的card接口
@"mqqapi://card/show_pslcard?src_type=internal&version=1&app_name=%@&req_type=0&title=%@"
];
NSString *appName = [self encodeString:kQQAppName];
NSString *defaultTitle = [self encodeString:@"分享内容"];
// 逐个尝试每种方案
[self tryURLSchemes:urlTemplates appName:appName title:defaultTitle index:0 completion:completion];
}
+ (void)tryURLSchemes:(NSArray *)urlTemplates
appName:(NSString *)appName
title:(NSString *)title
index:(NSInteger)index
completion:(void(^)(BOOL success))completion {
if (index >= urlTemplates.count) {
NSLog(@"所有URL方案都尝试失败");
if (completion) completion(NO);
return;
}
NSString *template = urlTemplates[index];
NSString *urlString;
// 根据模板格式构造URL
if ([template containsString:@"chat_type=select"] ||
[template containsString:@"friend_list"] ||
[template containsString:@"im/recent"]) {
// 不需要参数的URL
urlString = template;
} else if ([template containsString:@"file_data"]) {
// 需要两个参数的URL
urlString = [NSString stringWithFormat:template, title, appName];
} else {
// 需要app_name和title的URL
urlString = [NSString stringWithFormat:template, appName, title];
}
NSURL *url = [NSURL URLWithString:urlString];
NSLog(@"尝试方案%ld: %@", (long)(index + 1), urlString);
if ([[UIApplication sharedApplication] canOpenURL:url]) {
if (@available(iOS 10.0, *)) {
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:^(BOOL success) {
if (success) {
NSLog(@"方案%ld 成功打开QQ", (long)(index + 1));
// 延迟检查是否真的打开了会话选择
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if (completion) completion(YES);
});
} else {
NSLog(@"方案%ld 打开失败,尝试下一个", (long)(index + 1));
[self tryURLSchemes:urlTemplates appName:appName title:title index:index + 1 completion:completion];
}
}];
} else {
[[UIApplication sharedApplication] openURL:url];
if (completion) completion(YES);
}
} else {
NSLog(@"方案%ld 不支持,尝试下一个", (long)(index + 1));
[self tryURLSchemes:urlTemplates appName:appName title:title index:index + 1 completion:completion];
}
}
+ (void)tryMultipleQQShareMethods:(NSString *)title
description:(NSString *)description
completion:(void(^)(BOOL success))completion {
NSLog(@"使用多种方式尝试QQ分享...");
// 检查QQ是否安装
if (![self isQQInstalled]) {
NSLog(@"QQ未安装");
if (completion) completion(NO);
return;
}
// 方法1: 先尝试强制弹出会话选择器
[self forceOpenQQSessionSelector:^(BOOL success) {
if (success) {
NSLog(@"成功弹出会话选择器");
if (completion) completion(YES);
} else {
NSLog(@"会话选择器失败,尝试简化分享");
// 方法2: 使用简化分享
[self simpleShareToQQFriend:title description:description url:nil completion:^(BOOL simpleSuccess) {
if (simpleSuccess) {
NSLog(@"简化分享成功");
if (completion) completion(YES);
} else {
NSLog(@"简化分享也失败,使用标准分享");
// 方法3: 使用标准分享
[self shareToQQFriend:QQShareTypeText
title:title
description:description
thumbImage:nil
url:nil
image:nil
completion:completion];
}
}];
}
}];
}
+ (void)shareWithSystemShare:(NSString *)title
description:(NSString *)description
url:(NSString *)url
fromViewController:(UIViewController *)viewController
completion:(void (^)(BOOL))completion {
// 准备分享内容数组
NSMutableArray *shareItems = [NSMutableArray array];
// 组合完整的分享文本不包含URL
NSMutableString *shareText = [NSMutableString string];
// 添加标题
if (title && title.length > 0) {
[shareText appendString:title];
}
// 添加描述
if (description && description.length > 0) {
if (shareText.length > 0) {
[shareText appendString:@"\n"]; // 使用单个换行符,更紧凑
}
[shareText appendString:description];
}
// 添加组合文本到分享项目(在组合完成后添加)
if (shareText.length > 0) {
[shareItems addObject:[shareText copy]];
NSLog(@"🔍 ✅ 添加组合文本: %@", shareText);
}
// 统一使用固定的分享URL不管传入的URL是什么
NSString *fixedShareURL = @"http://game.hudong.com";
NSURL *shareURL = [NSURL URLWithString:fixedShareURL];
if (shareURL) {
[shareItems addObject:shareURL];
NSLog(@"🔍 ✅ 添加固定分享URL: %@", fixedShareURL);
}
// 添加应用桌面图标作为缩略图
UIImage *appIcon = [self getAppIcon];
if (appIcon) {
[shareItems addObject:appIcon];
NSLog(@"🔍 ✅ 添加应用桌面图标作为缩略图");
}
// 如果没有任何分享内容,使用默认文本
if (shareItems.count == 0) {
[shareItems addObject:@"来自进贤聚友棋牌的精彩内容分享"];
NSURL *defaultURL = [NSURL URLWithString:fixedShareURL];
if (defaultURL) {
[shareItems addObject:defaultURL];
}
}
// 详细的调试日志
NSLog(@"🔍 ======== 系统分享内容详情 ========");
NSLog(@"🔍 原始标题: %@", title ?: @"(无)");
NSLog(@"🔍 原始描述: %@", description ?: @"(无)");
NSLog(@"🔍 传入URL: %@", url ?: @"(无)");
NSLog(@"🔍 实际分享URL: http://game.hudong.com (固定)");
NSLog(@"🔍 分享文本: %@", shareText.length > 0 ? shareText : @"(无)");
NSLog(@"🔍 分享项目数量: %lu", (unsigned long)shareItems.count);
// 打印所有分享项目
for (NSInteger i = 0; i < shareItems.count; i++) {
id item = shareItems[i];
if ([item isKindOfClass:[NSString class]]) {
NSLog(@"🔍 项目%ld (文本): %@", (long)i+1, item);
} else if ([item isKindOfClass:[NSURL class]]) {
NSLog(@"🔍 项目%ld (URL): %@", (long)i+1, [(NSURL *)item absoluteString]);
} else {
NSLog(@"🔍 项目%ld (其他): %@", (long)i+1, item);
}
}
NSLog(@"🔍 =====================================");
// 创建系统分享控制器
UIActivityViewController *activityVC = [[UIActivityViewController alloc]
initWithActivityItems:shareItems
applicationActivities:nil];
// 排除一些不常用的分享选项可选提高QQ等主要应用的显示优先级
NSArray *excludedActivityTypes = @[
UIActivityTypePostToVimeo,
UIActivityTypePostToFlickr,
UIActivityTypePostToTencentWeibo,
UIActivityTypeAssignToContact,
UIActivityTypeSaveToCameraRoll,
UIActivityTypeAddToReadingList,
UIActivityTypePostToFacebook,
UIActivityTypePostToTwitter
];
activityVC.excludedActivityTypes = excludedActivityTypes;
// 设置完成回调
activityVC.completionWithItemsHandler = ^(UIActivityType activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
NSLog(@"🔍 ======== 系统分享结果详情 ========");
NSLog(@"🔍 分享结果: %@", completed ? @"✅ 成功" : @"❌ 取消/失败");
NSLog(@"🔍 分享到应用: %@", activityType ?: @"(未知)");
if (activityError) {
NSLog(@"🔍 分享错误: %@", activityError.localizedDescription);
// 特别处理 RunningBoard 相关错误
if ([activityError.domain isEqualToString:@"RBSServiceErrorDomain"]) {
NSLog(@"🔍 ⚠️ 检测到RunningBoard权限错误这通常是系统级权限问题");
NSLog(@"🔍 ⚠️ 建议检查应用是否在前台,以及设备权限设置");
}
}
// 特别标记QQ分享
if (activityType && ([activityType containsString:@"QQ"] || [activityType containsString:@"qq"])) {
NSLog(@"🔍 ✅ QQ分享完成");
}
NSLog(@"🔍 =====================================");
if (completion) {
completion(completed);
}
};
// 在iPad上需要设置popover
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
activityVC.popoverPresentationController.sourceView = viewController.view;
activityVC.popoverPresentationController.sourceRect = CGRectMake(viewController.view.bounds.size.width/2, viewController.view.bounds.size.height/2, 0, 0);
activityVC.popoverPresentationController.permittedArrowDirections = 0;
}
// 确保在主线程呈现分享面板避免RunningBoard权限错误
dispatch_async(dispatch_get_main_queue(), ^{
// 再次检查视图控制器是否有效
if (viewController && viewController.view.window) {
NSLog(@"🔍 在主线程呈现系统分享面板");
[viewController presentViewController:activityVC animated:YES completion:^{
NSLog(@"🔍 ✅ 系统分享面板呈现完成");
}];
} else {
NSLog(@"🔍 ❌ 视图控制器无效或不在窗口层次结构中");
if (completion) {
completion(NO);
}
}
});
}
+ (void)shareWithSystemShareAuto:(NSString *)title
description:(NSString *)description
url:(NSString *)url
completion:(void (^)(BOOL))completion {
// 检查是否可以安全呈现分享面板
if (![self canSafelyPresentSharePanel]) {
NSLog(@"🔍 ❌ 当前条件不允许呈现分享面板避免RunningBoard错误");
if (completion) {
completion(NO);
}
return;
}
UIViewController *topViewController = [self getTopViewController];
if (!topViewController) {
NSLog(@"❌ 无法获取顶层视图控制器,无法弹出系统分享面板");
if (completion) {
completion(NO);
}
return;
}
[self shareWithSystemShare:title
description:description
url:url
fromViewController:topViewController
completion:completion];
}
#pragma mark - Private Methods
+ (UIViewController *)getTopViewController {
// 检查应用状态避免在后台或非活跃状态访问UI
UIApplicationState appState = [UIApplication sharedApplication].applicationState;
if (appState != UIApplicationStateActive) {
NSLog(@"🔍 ⚠️ 应用不在活跃状态 (状态: %ld),可能导致权限错误", (long)appState);
// 仍然尝试获取,但记录警告
}
UIWindow *keyWindow = nil;
// iOS 13+ 获取keyWindow的方式
if (@available(iOS 13.0, *)) {
NSSet<UIScene *> *connectedScenes = [UIApplication sharedApplication].connectedScenes;
NSLog(@"🔍 当前连接的Scene数量: %lu", (unsigned long)connectedScenes.count);
for (UIWindowScene *windowScene in connectedScenes) {
NSLog(@"🔍 Scene状态: %ld", (long)windowScene.activationState);
if (windowScene.activationState == UISceneActivationStateForegroundActive) {
NSLog(@"🔍 找到前台活跃的WindowScene");
for (UIWindow *window in windowScene.windows) {
NSLog(@"🔍 检查Window: isKeyWindow=%d, isHidden=%d", window.isKeyWindow, window.isHidden);
if (window.isKeyWindow && !window.isHidden) {
keyWindow = window;
NSLog(@"🔍 ✅ 找到活跃的keyWindow");
break;
}
}
if (keyWindow) break;
}
}
}
// 兼容iOS 13以下版本
if (!keyWindow) {
NSLog(@"🔍 使用传统方式获取keyWindow");
keyWindow = [UIApplication sharedApplication].keyWindow;
}
// 如果还是没有尝试获取第一个可见window
if (!keyWindow) {
NSLog(@"🔍 尝试获取第一个可见window");
NSArray *windows = [UIApplication sharedApplication].windows;
for (UIWindow *window in windows) {
if (!window.isHidden && window.rootViewController) {
keyWindow = window;
NSLog(@"🔍 使用备选window");
break;
}
}
}
if (!keyWindow) {
NSLog(@"🔍 ❌ 无法获取任何有效的window这可能导致RunningBoard权限错误");
return nil;
}
// 检查window是否有rootViewController
if (!keyWindow.rootViewController) {
NSLog(@"🔍 ❌ keyWindow没有rootViewController");
return nil;
}
// 获取顶层视图控制器
UIViewController *topViewController = keyWindow.rootViewController;
NSLog(@"🔍 根视图控制器: %@", NSStringFromClass([topViewController class]));
// 遍历presented视图控制器
int presentedCount = 0;
while (topViewController.presentedViewController && presentedCount < 10) { // 防止无限循环
topViewController = topViewController.presentedViewController;
presentedCount++;
NSLog(@"🔍 Presented视图控制器 %d: %@", presentedCount, NSStringFromClass([topViewController class]));
}
// 处理UINavigationController
if ([topViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController *navController = (UINavigationController *)topViewController;
topViewController = navController.topViewController;
NSLog(@"🔍 导航控制器顶层: %@", NSStringFromClass([topViewController class]));
}
// 处理UITabBarController
if ([topViewController isKindOfClass:[UITabBarController class]]) {
UITabBarController *tabController = (UITabBarController *)topViewController;
topViewController = tabController.selectedViewController;
NSLog(@"🔍 标签控制器选中: %@", NSStringFromClass([topViewController class]));
// 再次检查是否是NavigationController
if ([topViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController *navController = (UINavigationController *)topViewController;
topViewController = navController.topViewController;
NSLog(@"🔍 标签内导航控制器顶层: %@", NSStringFromClass([topViewController class]));
}
}
// 最终验证
if (topViewController && topViewController.view.window) {
NSLog(@"🔍 ✅ 成功获取有效的顶层视图控制器: %@", NSStringFromClass([topViewController class]));
} else {
NSLog(@"🔍 ⚠️ 获取的视图控制器可能无效或不在window层次结构中");
}
return topViewController;
}
+ (BOOL)canSafelyPresentSharePanel {
NSLog(@"🔍 ======== 检查分享面板呈现条件 ========");
// 1. 检查应用状态
UIApplicationState appState = [UIApplication sharedApplication].applicationState;
NSLog(@"🔍 应用状态: %ld (0=Active, 1=Inactive, 2=Background)", (long)appState);
if (appState != UIApplicationStateActive) {
NSLog(@"🔍 ❌ 应用不在活跃状态,无法安全呈现分享面板");
return NO;
}
// 2. 检查是否有有效的视图控制器
UIViewController *topVC = [self getTopViewController];
if (!topVC) {
NSLog(@"🔍 ❌ 无法获取顶层视图控制器");
return NO;
}
if (!topVC.view.window) {
NSLog(@"🔍 ❌ 视图控制器不在window层次结构中");
return NO;
}
// 3. 检查是否已经有模态视图
if (topVC.presentedViewController) {
NSLog(@"🔍 ❌ 已有模态视图控制器正在呈现: %@", NSStringFromClass([topVC.presentedViewController class]));
return NO;
}
// 4. 检查是否在主线程
if (![NSThread isMainThread]) {
NSLog(@"🔍 ❌ 不在主线程可能导致RunningBoard错误");
return NO;
}
// 5. iOS 13+ Scene状态检查
if (@available(iOS 13.0, *)) {
BOOL hasActiveScene = NO;
NSSet<UIScene *> *connectedScenes = [UIApplication sharedApplication].connectedScenes;
for (UIWindowScene *windowScene in connectedScenes) {
if ([windowScene isKindOfClass:[UIWindowScene class]] &&
windowScene.activationState == UISceneActivationStateForegroundActive) {
hasActiveScene = YES;
break;
}
}
if (!hasActiveScene) {
NSLog(@"🔍 ❌ 没有活跃的前台Scene");
return NO;
}
}
NSLog(@"🔍 ✅ 所有条件满足,可以安全呈现分享面板");
NSLog(@"🔍 =====================================");
return YES;
}
+ (NSString *)encodeString:(NSString *)string {
if (!string) return @"";
return [string stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
}
+ (NSString *)saveImageToTempDirectory:(UIImage *)image {
NSData *imageData = UIImageJPEGRepresentation(image, 0.7);
NSString *fileName = [NSString stringWithFormat:@"qq_share_%@.jpg", [self generateUUID]];
NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:fileName];
[imageData writeToFile:filePath atomically:YES];
return filePath;
}
+ (NSString *)generateUUID {
CFUUIDRef uuid = CFUUIDCreate(NULL);
CFStringRef uuidString = CFUUIDCreateString(NULL, uuid);
NSString *result = (__bridge_transfer NSString *)uuidString;
CFRelease(uuid);
return result;
}
+ (NSString *)getUrlParam:(NSString *)url paramName:(NSString *)name {
NSError *error;
NSString *regTags = [[NSString alloc] initWithFormat:@"(^|&|\\?)%@=([^&]*)(&|$)", name];
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regTags options:NSRegularExpressionCaseInsensitive error:&error];
NSTextCheckingResult *match = [regex firstMatchInString:url options:0 range:NSMakeRange(0, [url length])];
if (match) {
NSString *paramValue = [url substringWithRange:[match rangeAtIndex:2]];
return paramValue;
}
return nil;
}
+ (void)showAppNotInstalledAlert:(NSString *)appName {
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:[NSString stringWithFormat:@"%@未安装", appName]
message:[NSString stringWithFormat:@"您的设备未安装%@客户端,无法进行分享", appName]
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:nil];
[alertController addAction:okAction];
UIViewController *topVC = [self topViewController];
[topVC presentViewController:alertController animated:YES completion:nil];
});
}
+ (void)showAppIDConfigurationErrorAlert {
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"QQ分享配置错误"
message:@"QQ AppID配置错误请联系开发者检查配置"
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:nil];
[alertController addAction:okAction];
UIViewController *topVC = [self topViewController];
[topVC presentViewController:alertController animated:YES completion:nil];
});
}
+ (UIViewController *)topViewController {
UIViewController *rootViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
while (rootViewController.presentedViewController) {
rootViewController = rootViewController.presentedViewController;
}
if ([rootViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController *navigationController = (UINavigationController *)rootViewController;
return navigationController.visibleViewController;
}
if ([rootViewController isKindOfClass:[UITabBarController class]]) {
UITabBarController *tabBarController = (UITabBarController *)rootViewController;
UIViewController *selectedViewController = tabBarController.selectedViewController;
if ([selectedViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController *navigationController = (UINavigationController *)selectedViewController;
return navigationController.visibleViewController;
}
return selectedViewController;
}
return rootViewController;
}
+ (UIImage *)getAppLaunchImage {
// 保留此方法以备将来需要,但现在主要使用桌面图标
NSLog(@"🔍 ⚠️ 建议使用 getAppIcon 方法获取桌面图标");
return [self getAppIcon];
}
+ (UIImage *)getAppIcon {
// 尝试获取应用桌面图标
UIImage *appIcon = nil;
// 方法1: 从Info.plist获取图标信息
NSDictionary *infoPlist = [[NSBundle mainBundle] infoDictionary];
// iOS 13+ 支持的新格式
NSDictionary *icons = infoPlist[@"CFBundleIcons"];
NSDictionary *primaryIcon = icons[@"CFBundlePrimaryIcon"];
NSArray *iconFiles = primaryIcon[@"CFBundleIconFiles"];
if (iconFiles && iconFiles.count > 0) {
// 按优先级尝试不同尺寸的图标(从大到小)
NSArray *preferredSizes = @[@"180", @"120", @"60"];
for (NSString *size in preferredSizes) {
for (NSString *iconName in iconFiles) {
NSString *testName = [NSString stringWithFormat:@"%@%@", iconName, size];
appIcon = [UIImage imageNamed:testName];
if (appIcon) {
NSLog(@"🔍 ✅ 获取应用图标成功: %@", testName);
return appIcon;
}
}
}
// 尝试原始名称
for (NSString *iconName in iconFiles) {
appIcon = [UIImage imageNamed:iconName];
if (appIcon) {
NSLog(@"🔍 ✅ 获取应用图标成功: %@", iconName);
return appIcon;
}
}
}
// 方法2: 尝试常见的图标名称
NSArray *commonIconNames = @[
@"Icon-180", // iPhone @3x (180x180)
@"Icon180", // 常见命名
@"Icon-120", // iPhone @2x (120x120)
@"Icon120", // 常见命名
@"Icon-60", // iPhone @1x (60x60)
@"Icon60", // 常见命名
@"AppIcon60x60@3x",
@"AppIcon60x60@2x",
@"AppIcon60x60",
@"AppIcon", // 通用名称
@"Icon", // 简单名称
@"icon" // 小写
];
for (NSString *iconName in commonIconNames) {
appIcon = [UIImage imageNamed:iconName];
if (appIcon) {
NSLog(@"🔍 ✅ 获取应用图标成功: %@", iconName);
return appIcon;
}
}
// 方法3: 从App Bundle中搜索图标文件
NSBundle *mainBundle = [NSBundle mainBundle];
NSArray *imageExtensions = @[@"png", @"jpg", @"jpeg"];
for (NSString *ext in imageExtensions) {
NSArray *iconPaths = [mainBundle pathsForResourcesOfType:ext inDirectory:nil];
for (NSString *path in iconPaths) {
NSString *filename = [[path lastPathComponent] stringByDeletingPathExtension];
// 检查文件名是否包含icon相关关键词
if ([filename.lowercaseString containsString:@"icon"] ||
[filename.lowercaseString containsString:@"appicon"]) {
appIcon = [UIImage imageWithContentsOfFile:path];
if (appIcon) {
NSLog(@"🔍 ✅ 从Bundle获取应用图标: %@", filename);
return appIcon;
}
}
}
}
NSLog(@"🔍 ⚠️ 无法获取应用桌面图标,创建默认图标");
return [self createDefaultAppIcon];
}
+ (UIImage *)createDefaultAppIcon {
// 创建一个简单的默认应用图标
CGSize iconSize = CGSizeMake(120, 120);
UIGraphicsBeginImageContextWithOptions(iconSize, NO, [UIScreen mainScreen].scale);
// 设置渐变背景色(模拟应用图标的效果)
CGContextRef context = UIGraphicsGetCurrentContext();
// 创建渐变色
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGFloat colors[] = {
0.2, 0.6, 1.0, 1.0, // 蓝色
0.1, 0.4, 0.8, 1.0 // 深蓝色
};
CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, colors, NULL, 2);
// 绘制渐变背景
CGPoint startPoint = CGPointMake(0, 0);
CGPoint endPoint = CGPointMake(iconSize.width, iconSize.height);
CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);
// 释放资源
CGGradientRelease(gradient);
CGColorSpaceRelease(colorSpace);
// 添加圆角效果模拟iOS图标圆角
UIBezierPath *roundedRect = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, iconSize.width, iconSize.height) cornerRadius:iconSize.width * 0.2];
[roundedRect addClip];
// 添加文字
NSString *text = @"聚友\n棋牌";
NSDictionary *attributes = @{
NSFontAttributeName: [UIFont boldSystemFontOfSize:18],
NSForegroundColorAttributeName: [UIColor whiteColor],
NSParagraphStyleAttributeName: ({
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
style.alignment = NSTextAlignmentCenter;
style;
})
};
CGSize textSize = [text boundingRectWithSize:iconSize
options:NSStringDrawingUsesLineFragmentOrigin
attributes:attributes
context:nil].size;
CGRect textRect = CGRectMake((iconSize.width - textSize.width) / 2,
(iconSize.height - textSize.height) / 2,
textSize.width,
textSize.height);
[text drawInRect:textRect withAttributes:attributes];
UIImage *defaultIcon = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSLog(@"🔍 ✅ 创建默认应用图标");
return defaultIcon;
}
+ (NSString *)validateAndFixURL:(NSString *)url {
if (!url || url.length == 0) {
return nil;
}
// 移除首尾空格
NSString *trimmedURL = [url stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSLog(@"🔍 开始验证URL: %@", trimmedURL);
// 检查是否是自定义scheme如http://sharegame/...
if ([trimmedURL hasPrefix:@"http://sharegame/"] || [trimmedURL hasPrefix:@"https://sharegame/"]) {
// 将自定义的sharegame域名替换为合法的域名
NSString *fixedURL = [trimmedURL stringByReplacingOccurrencesOfString:@"http://sharegame/" withString:@"https://game.example.com/"];
fixedURL = [fixedURL stringByReplacingOccurrencesOfString:@"https://sharegame/" withString:@"https://game.example.com/"];
NSLog(@"🔍 修复自定义域名URL: %@ -> %@", trimmedURL, fixedURL);
return fixedURL;
}
// 检查是否已经有协议头
if (![trimmedURL hasPrefix:@"http://"] && ![trimmedURL hasPrefix:@"https://"] && ![trimmedURL hasPrefix:@"ftp://"]) {
// 如果没有协议头添加https://
NSString *fixedURL = [@"https://" stringByAppendingString:trimmedURL];
NSLog(@"🔍 添加协议头: %@ -> %@", trimmedURL, fixedURL);
return fixedURL;
}
// 验证URL是否有效
NSURL *testURL = [NSURL URLWithString:trimmedURL];
if (testURL && testURL.scheme && testURL.host) {
NSLog(@"🔍 ✅ URL格式有效: %@", trimmedURL);
return trimmedURL;
}
// 如果URL无效尝试进行URL编码
NSString *encodedURL = [trimmedURL stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
if (encodedURL) {
NSURL *encodedTestURL = [NSURL URLWithString:encodedURL];
if (encodedTestURL && encodedTestURL.scheme && encodedTestURL.host) {
NSLog(@"🔍 ✅ URL编码后有效: %@ -> %@", trimmedURL, encodedURL);
return encodedURL;
}
}
NSLog(@"🔍 ❌ URL无法修复将作为文本处理: %@", trimmedURL);
return nil;
}
+ (void)shareWithSystemShareContent:(id)shareContent
completion:(void (^ _Nullable)(BOOL success))completion {
NSLog(@"🔍 [QQShareManager] 开始使用ShareContent对象进行系统分享");
// 主线程检查
if (![NSThread isMainThread]) {
NSLog(@"⚠️ [QQShareManager] 检测到非主线程调用,切换到主线程");
dispatch_async(dispatch_get_main_queue(), ^{
[self shareWithSystemShareContent:shareContent completion:completion];
});
return;
}
// 权限检查
if (![self canSafelyPresentSharePanel]) {
NSLog(@"❌ [QQShareManager] 无法安全呈现系统分享面板");
if (completion) {
completion(NO);
}
return;
}
// 检查ShareContent对象
if (!shareContent) {
NSLog(@"❌ [QQShareManager] ShareContent对象为空");
if (completion) {
completion(NO);
}
return;
}
// 通过KVC从ShareContent对象中提取参数
NSString *title = nil;
NSString *description = nil;
NSString *url = nil;
NSString *type = nil;
@try {
// 尝试获取标题
if ([shareContent respondsToSelector:@selector(valueForKey:)]) {
title = [shareContent valueForKey:@"title"];
description = [shareContent valueForKey:@"desc"];
url = [shareContent valueForKey:@"webpageUrl"];
type = [shareContent valueForKey:@"type"];
}
NSLog(@"🔍 [QQShareManager] 从ShareContent提取参数:");
NSLog(@"🔍 - 标题: %@", title ?: @"(无)");
NSLog(@"🔍 - 描述: %@", description ?: @"(无)");
NSLog(@"🔍 - 链接: %@", url ?: @"(无)");
NSLog(@"🔍 - 类型: %@", type ?: @"(无)");
} @catch (NSException *exception) {
NSLog(@"❌ [QQShareManager] 解析ShareContent时发生异常: %@", exception.reason);
if (completion) {
completion(NO);
}
return;
}
// 检查分享类型,决定分享方式
BOOL isScreenshotShare = [type intValue] == 2;
NSLog(@"🔍 [QQShareManager] 分享类型: %@", isScreenshotShare ? @"截图分享" : @"文本分享");
// 设置默认值
if (!title || title.length == 0) {
title = isScreenshotShare ? @"游戏截图分享" : @"游戏分享";
}
if (!description || description.length == 0) {
description = isScreenshotShare ? @"精彩游戏画面分享" : @"精彩游戏内容分享";
}
// 构建分享内容项
NSMutableArray *shareItems = [NSMutableArray array];
if (isScreenshotShare) {
// 截图分享模式
NSLog(@"🔍 [QQShareManager] 执行截图分享");
// 获取屏幕截图
UIImage *screenImage = [FuncPublic getImageWithFullScreenshot];
if (screenImage) {
[shareItems addObject:screenImage];
NSLog(@"🔍 [QQShareManager] 添加屏幕截图,尺寸: %.0fx%.0f", screenImage.size.width, screenImage.size.height);
description = @"精彩游戏画面分享";
// 为截图添加文字说明
NSString *combinedText = nil;
if (title && description) {
combinedText = [NSString stringWithFormat:@"%@\n%@", title, description];
} else if (title) {
combinedText = title;
} else if (description) {
combinedText = description;
}
if (combinedText) {
[shareItems addObject:combinedText];
NSLog(@"🔍 [QQShareManager] 添加截图说明文字: %@", combinedText);
}
} else {
NSLog(@"❌ [QQShareManager] 截图获取失败,降级为文本分享");
isScreenshotShare = NO; // 降级处理
}
}
if (!isScreenshotShare) {
// 纯文本分享模式真正的纯文本不包含URL和图标
NSLog(@"🔍 [QQShareManager] 执行纯文本分享(仅文本内容)");
// 组合完整的分享文本
NSMutableString *shareText = [NSMutableString string];
// 添加标题
if (title && title.length > 0) {
[shareText appendString:title];
}
// 添加描述
if (description && description.length > 0) {
if (shareText.length > 0) {
[shareText appendString:@"\n\n"]; // 使用单个换行符
}
[shareText appendString:description];
}
// 仅添加组合文本到分享项目(纯文本分享)
if (shareText.length > 0) {
[shareItems addObject:[shareText copy]];
NSLog(@"🔍 [QQShareManager] 添加纯文本内容: %@", shareText);
} else {
// 如果没有任何文本,使用默认文本
[shareItems addObject:@"来自进贤聚友棋牌的精彩内容分享"];
NSLog(@"🔍 [QQShareManager] 使用默认纯文本内容");
}
// 纯文本分享不添加URL不添加应用图标
NSLog(@"🔍 [QQShareManager] 纯文本分享模式不包含URL和图标");
}
// 检查分享内容
if (shareItems.count == 0) {
NSLog(@"❌ [QQShareManager] 没有有效的分享内容");
if (completion) {
completion(NO);
}
return;
}
// 详细的调试日志
NSLog(@"🔍 ======== ShareContent系统分享详情 ========");
NSLog(@"🔍 分享类型: %@", isScreenshotShare ? @"截图分享" : @"纯文本分享");
NSLog(@"🔍 原始标题: %@", title ?: @"(无)");
NSLog(@"🔍 原始描述: %@", description ?: @"(无)");
NSLog(@"🔍 传入URL: %@", url ?: @"(无)");
if (!isScreenshotShare) {
NSLog(@"🔍 纯文本模式不包含URL和图标");
}
NSLog(@"🔍 type字段: %@", type ?: @"(无)");
NSLog(@"🔍 分享项目数量: %lu", (unsigned long)shareItems.count);
// 打印所有分享项目与shareWithSystemShare保持一致
for (NSInteger i = 0; i < shareItems.count; i++) {
id item = shareItems[i];
if ([item isKindOfClass:[NSString class]]) {
NSLog(@"🔍 项目%ld (文本): %@", (long)i+1, item);
} else if ([item isKindOfClass:[NSURL class]]) {
NSLog(@"🔍 项目%ld (URL): %@", (long)i+1, [(NSURL *)item absoluteString]);
} else if ([item isKindOfClass:[UIImage class]]) {
UIImage *image = (UIImage *)item;
NSLog(@"🔍 项目%ld (图片): %.0fx%.0f", (long)i+1, image.size.width, image.size.height);
} else {
NSLog(@"🔍 项目%ld (其他): %@", (long)i+1, item);
}
}
NSLog(@"🔍 =========================================");
NSLog(@"🔍 [QQShareManager] 准备分享 %lu 个项目", (unsigned long)shareItems.count);
// 获取顶层视图控制器
UIViewController *topViewController = [self getTopViewController];
if (!topViewController) {
NSLog(@"❌ [QQShareManager] 无法获取顶层视图控制器");
if (completion) {
completion(NO);
}
return;
}
// 创建UIActivityViewController
UIActivityViewController *activityVC = [[UIActivityViewController alloc]
initWithActivityItems:shareItems
applicationActivities:nil];
// 排除不需要的分享选项(可选)
activityVC.excludedActivityTypes = @[
UIActivityTypeAssignToContact,
UIActivityTypePostToVimeo,
UIActivityTypePrint,
UIActivityTypeAirDrop // 排除AirDrop避免意外分享
];
// 设置完成回调与shareWithSystemShare保持一致的日志格式
activityVC.completionWithItemsHandler = ^(UIActivityType activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
NSLog(@"🔍 ======== ShareContent分享结果详情 ========");
NSLog(@"🔍 分享结果: %@", completed ? @"✅ 成功" : @"❌ 取消/失败");
NSLog(@"🔍 分享到应用: %@", activityType ?: @"(未知)");
if (activityError) {
NSLog(@"🔍 分享错误: %@", activityError.localizedDescription);
// 特别处理 RunningBoard 相关错误与shareWithSystemShare一致
if ([activityError.domain isEqualToString:@"RBSServiceErrorDomain"]) {
NSLog(@"🔍 ⚠️ 检测到RunningBoard权限错误这通常是系统级权限问题");
NSLog(@"🔍 ⚠️ 建议检查应用是否在前台,以及设备权限设置");
}
if (completion) {
completion(NO);
}
return;
}
// 特别标记QQ分享与shareWithSystemShare一致
if (activityType && ([activityType containsString:@"QQ"] || [activityType containsString:@"qq"])) {
NSLog(@"🔍 ✅ QQ分享完成");
}
NSLog(@"🔍 =========================================");
if (completion) {
completion(completed);
}
};
// iPad适配 - 设置popover
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
if (activityVC.popoverPresentationController) {
activityVC.popoverPresentationController.sourceView = topViewController.view;
activityVC.popoverPresentationController.sourceRect = CGRectMake(
topViewController.view.bounds.size.width / 2,
topViewController.view.bounds.size.height / 2,
1, 1
);
activityVC.popoverPresentationController.permittedArrowDirections = 0;
}
}
// 呈现分享面板
[topViewController presentViewController:activityVC animated:YES completion:^{
NSLog(@"🔍 [QQShareManager] 系统分享面板已呈现");
}];
}
@end