
主要变更: 1. 新增 ep_splash.png 作为应用启动时的展示图像。 2. 更新 Info.plist 中的应用名称和相关描述,替换为 "E-Parti"。 3. 引入 EPSignatureColorGuideView 和 EPEmotionColorStorage,支持用户选择和保存专属情绪颜色。 4. 在 AppDelegate 中集成情绪颜色引导逻辑,确保用户首次登录时能够选择专属颜色。 此更新旨在提升用户体验,增强应用的品牌识别度,并提供个性化的情绪表达功能。
272 lines
11 KiB
Objective-C
272 lines
11 KiB
Objective-C
//
|
||
// ShareHelder.m
|
||
// YuMi
|
||
//
|
||
// Created by P on 2025/3/6.
|
||
//
|
||
|
||
#import <UIKit/UIKit.h>
|
||
#import "ShareHelder.h"
|
||
#import "ShareProvider.h"
|
||
#import <LinkPresentation/LinkPresentation.h>
|
||
|
||
// 添加静态变量追踪当前的分享控制器
|
||
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-Parti ——",
|
||
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-Parti的精彩推荐";
|
||
NSString *appName = @"E-Parti";
|
||
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
|