// // ShareHelder.m // YuMi // // Created by P on 2025/3/6. // #import #import "ShareHelder.h" #import "ShareProvider.h" #import // 添加静态变量追踪当前的分享控制器 static UIActivityViewController *_currentActivityVC = nil; static NSTimer *_timeoutTimer = nil; static __weak UIViewController *_presentingVC = nil; @implementation ShareHelder + (NSDictionary *)extractURLAndRemainingStringFromString:(NSString *)inputString { // 创建正则表达式,匹配 URL NSError *error = NULL; NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"https?://[^\\s]+" options:NSRegularExpressionCaseInsensitive error:&error]; if (error) { // NSLog(@"Error creating regex: %@", error); return @{@"url": @"", @"remainingString": inputString}; } // 查找匹配的 URL NSTextCheckingResult *match = [regex firstMatchInString:inputString options:0 range:NSMakeRange(0, inputString.length)]; if (match) { // 提取匹配的 URL NSRange urlRange = [match range]; NSString *url = [inputString substringWithRange:urlRange]; // 提取分离 URL 后的字符串 NSString *remainingString; if (urlRange.location + urlRange.length < inputString.length) { remainingString = [inputString substringFromIndex:urlRange.location + urlRange.length]; } else { remainingString = @""; } return @{@"url": url, @"remainingString": remainingString}; } // 如果没有找到 URL,返回原始字符串 return @{@"url": @"", @"remainingString": inputString}; } + (NSString *)extractURLFromString:(NSString *)inputString { // 创建正则表达式,匹配 URL NSError *error = NULL; NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"https?://[^\\s]+" options:NSRegularExpressionCaseInsensitive error:&error]; if (error) { // NSLog(@"Error creating regex: %@", error); return @""; } // 查找匹配的 URL NSTextCheckingResult *match = [regex firstMatchInString:inputString options:0 range:NSMakeRange(0, inputString.length)]; if (match) { // 提取匹配的 URL NSRange urlRange = [match range]; return [inputString substringWithRange:urlRange]; } return @""; } + (void)shareImage:(UIImage *)image url:(NSString *)urlString fromController:(UIViewController *)viewController { #if DEBUG urlString = [urlString stringByReplacingOccurrencesOfString:@"https" withString:@"http"]; #endif // 1. 解析URL和文本 NSDictionary *dic = [self extractURLAndRemainingStringFromString:urlString]; NSString *remainingText = [dic objectForKey:@"remainingString"]; NSString *urlStr = [dic objectForKey:@"url"]; NSURL *url = urlStr.length > 0 ? [NSURL URLWithString:urlStr] : nil; // 2. 准备分享内容 NSString *title = @"🎵 发现精彩内容"; NSString *subtitle = remainingText.length > 0 ? remainingText : @"快来看看这个有趣的内容吧!"; NSString *appName = [YYUtility appName]; // 3. 获取应用图标 UIImage *appIcon = [UIImage imageNamed:@"AppIcon"] ?: [UIImage imageNamed:@"app_icon"]; if (!appIcon) { // 尝试从bundle获取应用图标 NSString *iconPath = [[NSBundle mainBundle] pathForResource:@"AppIcon60x60" ofType:@"png"]; if (iconPath) { appIcon = [UIImage imageWithContentsOfFile:iconPath]; } } // 准备多种格式的分享内容 NSMutableArray *shareItems = [NSMutableArray array]; // 1. 添加纯文本(用于备忘录等文本应用) NSString *plainText = [NSString stringWithFormat:@"🎵 发现精彩内容\n\n%@\n\n🔗 %@\n\n—— 来自 E-Party ——", subtitle, url.absoluteString ?: @""]; [shareItems addObject:plainText]; // 2. 添加URL(用于浏览器、阅读列表等) if (url) { [shareItems addObject:url]; } // 3. 添加图片(用于相册、图片编辑等) if (image) { [shareItems addObject:image]; } // 4. 添加增强的ShareProvider(用于高级自定义) ShareProvider *shareProvider = [[ShareProvider alloc] initWithTitle:title subtitle:subtitle appName:appName url:url image:image appIcon:appIcon]; [shareItems addObject:shareProvider]; // 创建ActivityViewController UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:shareItems.copy applicationActivities:nil]; // 不排除任何系统分享类型,让用户看到所有选项 activityVC.excludedActivityTypes = nil; // 保存当前分享控制器的引用 _currentActivityVC = activityVC; _presentingVC = viewController; // 添加完成回调监控 activityVC.completionWithItemsHandler = ^(UIActivityType activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) { [self cleanupShareSession]; if (activityError) { NSLog(@"ShareHelder: Activity error occurred: %@", activityError.localizedDescription); // 错误发生时,确保界面能正常关闭 dispatch_async(dispatch_get_main_queue(), ^{ [self forceCloseShareSheet]; }); } }; // 8. 适配 iPad 弹出样式 if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { UIPopoverPresentationController *popover = activityVC.popoverPresentationController; if (popover) { popover.sourceView = viewController.view; popover.sourceRect = CGRectMake(viewController.view.bounds.size.width / 2, viewController.view.bounds.size.height / 2, 0, 0); popover.permittedArrowDirections = UIPopoverArrowDirectionAny; } } // 10. 设置超时保护定时器 _timeoutTimer = [NSTimer scheduledTimerWithTimeInterval:15.0 target:self selector:@selector(checkShareSheetTimeout) userInfo:nil repeats:NO]; // 11. 显示分享界面 [viewController presentViewController:activityVC animated:YES completion:nil]; } #pragma mark - 新增方法 + (void)forceCloseShareSheet { if (_currentActivityVC) { UIViewController *presentingVC = _currentActivityVC.presentingViewController; if (presentingVC) { [presentingVC dismissViewControllerAnimated:YES completion:^{ [self cleanupShareSession]; }]; } else if (_presentingVC) { [_presentingVC dismissViewControllerAnimated:YES completion:^{ [self cleanupShareSession]; }]; } } // 清理会话 [self cleanupShareSession]; } + (void)checkShareSheetTimeout { // 检查是否还有未关闭的分享弹窗 if (_currentActivityVC && _currentActivityVC.presentingViewController) { NSLog(@"ShareHelder: Share sheet timeout detected, attempting force close"); [self forceCloseShareSheet]; } } + (void)cleanupShareSession { // 清理定时器 if (_timeoutTimer) { [_timeoutTimer invalidate]; _timeoutTimer = nil; } // 清理引用 _currentActivityVC = nil; _presentingVC = nil; } + (void)__shareImage:(UIImage *)image url:(NSString *)urlString fromController:(UIViewController *)viewController { // 1. 准备分享内容 NSString *title = @"🎵 Apple Music 专辑推荐:Imagine Dragons"; NSString *subtitle = @"来自E-Party的精彩推荐"; NSString *appName = @"E-Party"; NSURL *albumURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@/%@", API_HOST_URL, urlString]]; UIImage *albumImage = image; // 2. 获取应用图标 UIImage *appIcon = [UIImage imageNamed:@"AppIcon"] ?: [UIImage imageNamed:@"app_icon"]; if (!appIcon) { // 尝试从bundle获取应用图标 NSString *iconPath = [[NSBundle mainBundle] pathForResource:@"AppIcon60x60" ofType:@"png"]; if (iconPath) { appIcon = [UIImage imageWithContentsOfFile:iconPath]; } } // 3. 创建自定义 ShareProvider(使用新的初始化方法) ShareProvider *musicShareProvider = [[ShareProvider alloc] initWithTitle:title subtitle:subtitle appName:appName url:albumURL image:albumImage appIcon:appIcon]; // 4. 创建分享项 NSArray *activityItems = @[musicShareProvider, albumImage]; // 5. 创建分享面板 UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:nil]; // 6. 设置排除的分享选项 activityVC.excludedActivityTypes = @[ UIActivityTypeAssignToContact, // 指定给联系人 UIActivityTypeSaveToCameraRoll, // 保存到相册 UIActivityTypePrint, // 打印 UIActivityTypeAddToReadingList, // 添加到 Safari 阅读列表 UIActivityTypeOpenInIBooks, // 在 iBooks 中打开 UIActivityTypeMarkupAsPDF // 标记 PDF ]; // 7. iPad 需要指定 `popoverPresentationController` if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { activityVC.popoverPresentationController.sourceView = viewController.view; activityVC.popoverPresentationController.sourceRect = CGRectMake(viewController.view.bounds.size.width / 2, viewController.view.bounds.size.height / 2, 0, 0); } // 8. 展示分享面板 [viewController presentViewController:activityVC animated:YES completion:nil]; } @end