// // 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位数字,当前长度:%lu,AppID:%@", (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 *)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 *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 *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