解决qq和抖音分享

This commit is contained in:
joywayer
2026-02-12 21:52:27 +08:00
parent 09353155ec
commit 5944897a9d
5 changed files with 556 additions and 89 deletions

View File

@@ -5,4 +5,4 @@ platform :ios, '9.0'
target 'msext' do
# 添加七牛云SDK
pod 'Qiniu', '~> 8.0'
end
end

View File

@@ -174,6 +174,14 @@ typedef NS_ENUM(NSInteger, QQShareType) {
+ (void)shareWithSystemShareContent:(id)shareContent
completion:(void (^ _Nullable)(BOOL success))completion;
/**
* 分享到QQ直接拉起QQ不使用系统面板
* @param shareContent 完整的分享内容对象
* @param completion 分享完成回调
*/
+ (void)shareWithContent:(id)shareContent
completion:(void (^ _Nullable)(BOOL success))completion;
@end
NS_ASSUME_NONNULL_END

View File

@@ -8,9 +8,101 @@
#import "QQShareManager.h"
#import "FuncPublic.h" //
#import <LinkPresentation/LinkPresentation.h> // LinkPresentation
// TencentOpenAPI SDK
#if __has_include(<TencentOpenAPI/QQApiInterface.h>)
#import <TencentOpenAPI/QQApiInterface.h>
#import <TencentOpenAPI/TencentOAuth.h>
#define HAS_QQ_SDK 1
#else
#define HAS_QQ_SDK 0
#endif
// -----------------------------------------------------------------------------
// QQShareActivityItemSource
// This class is used to customize the preview title and icon in the Share Sheet.
// -----------------------------------------------------------------------------
@interface QQShareActivityItemSource : NSObject <UIActivityItemSource>
@property (nonatomic, strong) id content; // URL, String, or Image
@property (nonatomic, strong) NSString *title; // Preview Title
@property (nonatomic, strong) UIImage *image; // Preview Image (Icon)
@property (nonatomic, strong) NSString *desc; // Preview Description (Optional)
- (instancetype)initWithContent:(id)content title:(NSString *)title image:(UIImage *)image description:(NSString *)desc;
@end
@implementation QQShareActivityItemSource
- (instancetype)initWithContent:(id)content title:(NSString *)title image:(UIImage *)image description:(NSString *)desc {
self = [super init];
if (self) {
_content = content;
_title = title;
_image = image;
_desc = desc;
}
return self;
}
#pragma mark - UIActivityItemSource Methods
- (id)activityViewControllerPlaceholderItem:(UIActivityViewController *)activityViewController {
// Placeholder matches the content type
return self.content;
}
- (id)activityViewController:(UIActivityViewController *)activityViewController itemForActivityType:(UIActivityType)activityType {
// Return the actual content to share
return self.content;
}
// Ensure the preview metadata is provided (iOS 13+)
- (LPLinkMetadata *)activityViewControllerLinkMetadata:(UIActivityViewController *)activityViewController API_AVAILABLE(ios(13.0)) {
LPLinkMetadata *metadata = [[LPLinkMetadata alloc] init];
// Set Preview Title (User requested App Name or specific title)
metadata.title = self.title ? self.title : @"分享内容";
// Set Preview Icon / Image
// "图片分享正常,但其他情况(链接分享)图标有白边"
// : LPLinkMetadata content-type URL preview
// image iconProvideriOS "Icon"
// image imageProvideriOS "Image/Thumbnail"
// "图片分享" imageProvider
// NSItemProvider
// system share sheet
// 1. imageProvider (Thumbnail) padding
// 2. iconProvider
// :
// imageProvider URL Share Layout Sidebar
// 使 imageProvider Icon
if (self.image) {
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithObject:self.image];
metadata.imageProvider = itemProvider; // imageProvider
metadata.iconProvider = itemProvider; //
}
// Set Original URL (if content is URL)
if ([self.content isKindOfClass:[NSURL class]]) {
metadata.originalURL = (NSURL *)self.content;
metadata.URL = (NSURL *)self.content;
}
return metadata;
}
@end
// QQ URL Schemes
#define kQQScheme @"mqqapi://"
#define kQQShareScheme @"mqqapi://share/"
#define kQQFriendScheme @"mqqapi://share/to_fri?"
#define kQQZoneScheme @"mqqapi://share/to_qzone?"
@@ -101,117 +193,350 @@ static void(^QQShareCompletion)(BOOL) = nil;
//
QQShareCompletion = completion;
// URL - 使QQ900101
// URL parameters based on OpenShare implementation logic to fix 900101
// 900101 is often "Invalid AppID" or "Signature Mismatch".
// OpenShare uses Base64 for almost all text fields.
NSMutableString *urlString = [NSMutableString stringWithString:kQQFriendScheme];
// QQ
// 1. Basic Parameters
[urlString appendString:@"version=1"];
[urlString appendString:@"&cflag=0"];
[urlString appendString:@"&src_type=app"];
[urlString appendString:@"&src_type=app"]; // Required
// [urlString appendString:@"&cflag=0"]; // OpenShare doesn't always send this, but let's keep it off for now or 0
// 2. App Identification
// thirdAppDisplayName MUST be Base64 encoded for mqqapi usually
NSString *base64Name = [self base64Encode:kQQAppName];
NSString *encodedName = [self encodeString:base64Name];
[urlString appendFormat:@"&thirdAppDisplayName=%@", encodedName];
[urlString appendFormat:@"&app_name=%@", encodedName];
// 使QQ
[urlString appendFormat:@"&thirdAppDisplayName=%@", [self encodeString:kQQAppName]];
[urlString appendFormat:@"&app_id=%@", kQQAppID];
[urlString appendFormat:@"&sdkv=2.9.0"];
[urlString appendFormat:@"&sdkp=i"];
[urlString appendFormat:@"&share_id=%@", kQQAppID];
//
// 3. Callback
// mqqapi usually validates that callback_name matches "QQ" + Hex(AppID)
// 102793577 (Decimal) -> 06208169 (Hex)
// So callback_name should be QQ06208169
NSString *hexCallbackName = @"QQ06208169";
[urlString appendString:@"&callback_type=scheme"];
[urlString appendFormat:@"&callback_name=%@", [self encodeString:kQQCallbackScheme]];
[urlString appendFormat:@"&callback_name=%@", hexCallbackName];
// Bundle ID
NSString *bundleId = [[NSBundle mainBundle] bundleIdentifier];
// 4. Content Parameters
//
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]];
// -------------------------------------------------------------------------
//
// 1. useSystemShare: 使 iOS (UIActivityViewController)
// 2. useQQSDK: 使 SDK (TencentOpenAPI) - SDK
// 3. Fallback: 使 URL Scheme (mqqapi://) - SDK (Legacy)
// -------------------------------------------------------------------------
BOOL useSystemShare = NO; // NO
BOOL useQQSDK = NO; // YES, 使SDK
// :
BOOL runSystemShare = NO;
BOOL sdkIsAvailableAndEnabled = NO;
#if HAS_QQ_SDK
if (useQQSDK) sdkIsAvailableAndEnabled = YES;
#endif
if (sdkIsAvailableAndEnabled) {
// SDK SDK () SystemShare
runSystemShare = NO;
} else {
// SDK
if (useSystemShare) {
// ->
runSystemShare = YES;
} else {
//
// Scheme 使 SystemShare
if (type == QQShareTypeImage) {
runSystemShare = YES;
}
if (description && description.length > 0) {
[urlString appendFormat:@"&description=%@", [self encodeString:description]];
}
}
if (runSystemShare) {
NSMutableArray *activityItems = [NSMutableArray array];
// (App Icon)
UIImage *appIcon = [self getAppIcon];
// (App Name Title)
NSString *previewTitle = kQQAppName; // App
if (title && title.length > 0) {
previewTitle = title; // "App Name - Title"
}
// 使 QQShareActivityItemSource
if (@available(iOS 13.0, *)) {
switch (type) {
case QQShareTypeText:
if (description) {
// /
// NSString 使 UIActivityItemSource LPLinkMetadata
[activityItems addObject:description];
}
break;
case QQShareTypeImage:
if (image) {
//
// 使 ActivityItemSource
// Image image
[activityItems addObject:image];
}
break;
case QQShareTypeNews:
case QQShareTypeAudio:
case QQShareTypeVideo:
if (url) {
NSURL *shareURL = [NSURL URLWithString:url];
if (shareURL) {
// URL appIcon iconProvider
QQShareActivityItemSource *item = [[QQShareActivityItemSource alloc] initWithContent:shareURL title:previewTitle image:appIcon description:description];
[activityItems addObject:item];
}
}
// NSURL
// Title/Image App
// ItemSource URL
break;
}
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]];
} else {
// iOS 13 ()
switch (type) {
case QQShareTypeText:
if (title) [activityItems addObject:title];
if (description) [activityItems addObject:description];
break;
case QQShareTypeImage:
if (image) [activityItems addObject:image];
break;
case QQShareTypeNews:
case QQShareTypeAudio:
case QQShareTypeVideo:
if (url) {
NSURL *shareURL = [NSURL URLWithString:url];
if (shareURL) [activityItems addObject:shareURL];
}
if (title) [activityItems addObject:title];
// iOS 12
break;
}
}
if (activityItems.count > 0) {
NSLog(@"🔍 [QQShareManager] 策略: 使用系统 UIActivityViewController 分享");
dispatch_async(dispatch_get_main_queue(), ^{
UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:nil];
activityVC.completionWithItemsHandler = ^(UIActivityType _Nullable activityType, BOOL completed, NSArray * _Nullable returnedItems, NSError * _Nullable activityError) {
NSLog(@"[QQShareManager] 系统分享回调: completed=%d", completed);
if (completion) completion(completed);
};
UIViewController *topVC = [self topViewController];
if (topVC) {
if ([activityVC respondsToSelector:@selector(popoverPresentationController)]) {
activityVC.popoverPresentationController.sourceView = topVC.view;
activityVC.popoverPresentationController.sourceRect = CGRectMake(topVC.view.bounds.size.width/2.0, topVC.view.bounds.size.height/2.0, 1.0, 1.0);
activityVC.popoverPresentationController.permittedArrowDirections = 0;
}
[topVC presentViewController:activityVC animated:YES completion:nil];
} else {
if (completion) completion(NO);
}
if (description && description.length > 0) {
[urlString appendFormat:@"&description=%@", [self encodeString:description]];
});
return; // URL Scheme
}
}
#if HAS_QQ_SDK
// -------------------------------------------------------------------------
// : SDK
// -------------------------------------------------------------------------
if (useQQSDK) {
NSLog(@"🔍 [QQShareManager] 策略: 使用腾讯官方 SDK 分享");
// 线 (SDK)
dispatch_async(dispatch_get_main_queue(), ^{
QQApiObject *msgObj = nil;
switch (type) {
case QQShareTypeText: {
QQApiTextObject *textObj = [QQApiTextObject objectWithText:description ? description : @""];
textObj.title = title;
msgObj = textObj;
break;
}
case QQShareTypeImage: {
if (!image) {
if (completion) completion(NO);
return;
}
NSData *imgData = UIImageJPEGRepresentation(image, 0.8);
// Image Object
QQApiImageObject *imgObj = [QQApiImageObject objectWithData:imgData
previewImageData:imgData
title:title
description:description];
msgObj = imgObj;
break;
}
case QQShareTypeNews:
case QQShareTypeAudio:
case QQShareTypeVideo: {
if (!url) {
if (completion) completion(NO);
return;
}
NSData *previewData = nil;
if (thumbImage) {
previewData = UIImageJPEGRepresentation(thumbImage, 0.5);
}
NSURL *targetUrl = [NSURL URLWithString:url];
if (type == QQShareTypeAudio) {
QQApiAudioObject *audioObj = [QQApiAudioObject objectWithURL:targetUrl
title:title
description:description
previewImageData:previewData];
msgObj = audioObj;
} else if (type == QQShareTypeVideo) {
// Video usually needs flashURL, here acts as News Link basically
QQApiNewsObject *newsObj = [QQApiNewsObject objectWithURL:targetUrl
title:title
description:description
previewImageData:previewData];
msgObj = newsObj;
} else {
// News
QQApiNewsObject *newsObj = [QQApiNewsObject objectWithURL:targetUrl
title:title
description:description
previewImageData:previewData];
msgObj = newsObj;
}
break;
}
}
if (msgObj) {
SendMessageToQQReq *req = [SendMessageToQQReq reqWithContent:msgObj];
// QQ
QQApiSendResultCode sent = [QQApiInterface sendReq:req];
NSLog(@"[QQShareManager] SDK发送请求结果: %d", sent);
//
// : AppDelegate onResp
// EQQAPISENDSUCESS = 0
if (sent == 0) {
NSLog(@"✅ SDK请求发送成功");
// completion(YES)
} else {
NSLog(@"❌ SDK请求发送失败");
if (completion) completion(NO);
}
} else {
if (completion) {
completion(NO);
}
return;
NSLog(@"❌ [QQShareManager] 构建 SDK 对象失败");
if (completion) completion(NO);
}
});
return; // Scheme
}
#endif
// Falls through to Legacy Scheme Logic if useSystemShare is NO or activityItems is empty
switch (type) {
case QQShareTypeText:
[urlString appendString:@"&file_type=text"];
[urlString appendString:@"&req_type=0"]; // Text
if (title) [urlString appendFormat:@"&title=%@", [self encodeString:[self base64Encode:title]]];
if (description) [urlString appendFormat:@"&description=%@", [self encodeString:[self base64Encode:description]]];
break;
case QQShareTypeImage: {
if (!image) {
NSLog(@"❌ [QQShareManager] 图片对象为空");
if (completion) completion(NO);
return;
}
// URL Scheme (Dual Strategy)
// : Base64 () vs FilePath (/)
BOOL useBase64Scheme = YES;
if (useBase64Scheme) {
NSData *imgData = UIImageJPEGRepresentation(image, 0.5);
if (imgData.length > 1 * 1024 * 1024) imgData = UIImageJPEGRepresentation(image, 0.3);
NSString *base64Str = [imgData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
[urlString appendString:@"&file_type=image"];
[urlString appendFormat:@"&image_base64=%@", [self encodeString:base64Str]];
[urlString appendString:@"&cflag=0"];
} else {
NSString *imagePath = [self saveImageToDocumentsDirectory:image];
[urlString appendString:@"&file_type=image"];
[urlString appendString:@"&req_type=5"];
[urlString appendString:@"&cflag=0"];
UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
[pasteboard setData:UIImageJPEGRepresentation(image, 0.6) forPasteboardType:@"com.tencent.mqq.api.apiLargeData"];
if (title) [urlString appendFormat:@"&title=%@", [self encodeString:title]];
if (description) [urlString appendFormat:@"&description=%@", [self encodeString:description]];
NSString *fullPath = [@"file://" stringByAppendingString:imagePath];
NSString *encodedPath = [self encodeString:fullPath];
[urlString appendFormat:@"&file_path=%@", encodedPath];
[urlString appendFormat:@"&image_url=%@", encodedPath];
[urlString appendFormat:@"&object_location=%@", encodedPath];
}
break;
}
case QQShareTypeNews:
// "News" (Link) share
[urlString appendString:@"&file_type=news"];
[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 (title) [urlString appendFormat:@"&title=%@", [self encodeString:[self base64Encode:title]]];
if (description) [urlString appendFormat:@"&description=%@", [self encodeString:[self base64Encode:description]]];
if (url) [urlString appendFormat:@"&url=%@", [self encodeString:[self base64Encode:url]]];
if (thumbImage) {
NSString *thumbPath = [self saveImageToTempDirectory:thumbImage];
[urlString appendFormat:@"&previewimageUrl=%@", [self encodeString:[@"file://" stringByAppendingString:thumbPath]]];
NSString *thumbPath = [self saveImageToTempDirectory:thumbImage];
NSString *fullPath = [@"file://" stringByAppendingString:thumbPath];
// Preview Image URL often requires BASE64 of the path string for OpenShare compatibility
[urlString appendFormat:@"&previewimageUrl=%@", [self encodeString:[self base64Encode:fullPath]]];
}
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]]];
[urlString appendString:@"&file_type=audio"];
[urlString appendString:@"&req_type=2"];
if (title) [urlString appendFormat:@"&title=%@", [self encodeString:[self base64Encode:title]]];
if (description) [urlString appendFormat:@"&description=%@", [self encodeString:[self base64Encode:description]]];
if (url) [urlString appendFormat:@"&url=%@", [self encodeString:[self base64Encode:url]]];
if (thumbImage) {
NSString *thumbPath = [self saveImageToTempDirectory:thumbImage];
NSString *fullPath = [@"file://" stringByAppendingString:thumbPath];
[urlString appendFormat:@"&previewimageUrl=%@", [self encodeString:[self base64Encode:fullPath]]];
}
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]]];
}
// Video might be similar
break;
}
@@ -929,9 +1254,18 @@ static void(^QQShareCompletion)(BOOL) = nil;
return YES;
}
+ (NSString *)base64Encode:(NSString *)string {
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
return [data base64EncodedStringWithOptions:0];
}
+ (NSString *)encodeString:(NSString *)string {
if (!string) return @"";
return [string stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
// We must encode everything that is strictly reserved or unsafe in a query parameter value
// Especially + / = which are key for Base64
NSMutableCharacterSet *allowed = [[NSCharacterSet alphanumericCharacterSet] mutableCopy];
[allowed addCharactersInString:@"-._~"]; // Unreserved characters per RFC 3986
return [string stringByAddingPercentEncodingWithAllowedCharacters:allowed];
}
+ (NSString *)saveImageToTempDirectory:(UIImage *)image {
@@ -943,6 +1277,21 @@ static void(^QQShareCompletion)(BOOL) = nil;
return filePath;
}
+ (NSString *)saveImageToDocumentsDirectory:(UIImage *)image {
// Compress image to ensure it's not too large (similar to WeChat's 0.6 behavior)
NSData *imageData = UIImageJPEGRepresentation(image, 0.6);
NSString *fileName = [NSString stringWithFormat:@"qq_share_persistent_%@.jpg", [self generateUUID]];
// Use Documents directory for persistence
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths firstObject];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:fileName];
[imageData writeToFile:filePath atomically:YES];
NSLog(@"🔍 [QQShareManager] Saved image to Documents: %@", filePath);
return filePath;
}
+ (NSString *)generateUUID {
CFUUIDRef uuid = CFUUIDCreate(NULL);
CFStringRef uuidString = CFUUIDCreateString(NULL, uuid);
@@ -1029,7 +1378,24 @@ static void(^QQShareCompletion)(BOOL) = nil;
//
UIImage *appIcon = nil;
// 1: Info.plist
// 1.1: Asset Catalog "AppIcon-1"
// Xcode AppIcon Assets.car
// Info.plist CFBundleIcons () Xcode ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-1"
appIcon = [UIImage imageNamed:@"AppIcon-1"];
if (appIcon) {
NSLog(@"🔍 ✅ 获取应用图标成功: AppIcon-1");
return appIcon;
}
appIcon = [UIImage imageNamed:@"AppIcon"];
if (appIcon) {
NSLog(@"🔍 ✅ 获取应用图标成功: AppIcon");
return appIcon;
}
// 1.2: Info.plist
NSDictionary *infoPlist = [[NSBundle mainBundle] infoDictionary];
// iOS 13+
@@ -1471,4 +1837,86 @@ static void(^QQShareCompletion)(BOOL) = nil;
}];
}
+ (void)shareWithContent:(id)shareContent
completion:(void (^ _Nullable)(BOOL success))completion {
NSLog(@"🔍 [QQShareManager] 开始QQ直接分享(自动拉起会话选择)");
// QQ
if (![self isQQInstalled]) {
NSLog(@"❌ [QQShareManager] QQ未安装");
if (completion) {
completion(NO);
}
[self showAppNotInstalledAlert:@"QQ"];
return;
}
//
NSString *title = nil;
NSString *description = nil;
NSString *webpageUrl = nil;
NSString *type = nil;
@try {
if ([shareContent respondsToSelector:@selector(valueForKey:)]) {
title = [shareContent valueForKey:@"title"];
description = [shareContent valueForKey:@"desc"];
webpageUrl = [shareContent valueForKey:@"webpageUrl"];
type = [shareContent valueForKey:@"type"];
}
} @catch (NSException *exception) {
NSLog(@"❌ [QQShareManager] 参数提取异常: %@", exception);
if (completion) completion(NO);
return;
}
//
BOOL isScreenshotShare = [type intValue] == 2;
if (isScreenshotShare) {
// (Image)
UIImage *screenImage = [FuncPublic getImageWithFullScreenshot];
// image Base64UIImage
if (!screenImage) {
id imageObj = nil;
if ([shareContent respondsToSelector:@selector(valueForKey:)]) {
@try { imageObj = [shareContent valueForKey:@"image"]; } @catch (NSException *e) {}
}
if (imageObj && [imageObj isKindOfClass:[UIImage class]]) {
screenImage = imageObj;
} else if (imageObj && [imageObj isKindOfClass:[NSString class]]) {
NSData *data = [[NSData alloc] initWithBase64EncodedString:imageObj options:0];
if (data) screenImage = [UIImage imageWithData:data];
}
}
if (!screenImage) {
NSLog(@"❌ [QQShareManager] 截图失败且未通过参数传入图片");
if (completion) completion(NO);
return;
}
[self shareToQQFriend:QQShareTypeImage
title:title
description:description
thumbImage:nil
url:nil
image:screenImage
completion:completion];
} else {
// / (News)
// 使
UIImage *thumbImage = [self getAppIcon];
[self shareToQQFriend:QQShareTypeNews
title:title
description:description
thumbImage:thumbImage
url:webpageUrl
image:nil
completion:completion];
}
}
@end

View File

@@ -317,8 +317,9 @@ static SharePanel *sharedPanel = nil;
SharePanelCompletionBlock completionBlock = self.completionBlock;
// 使QQShareManagerQQ
[QQShareManager shareWithSystemShareContent:content
completion:^(BOOL success) {
// shareWithContentQQ
[QQShareManager shareWithContent:content
completion:^(BOOL success) {
NSLog(@"QQ分享结果: %@", success ? @"✅ 成功" : @"❌ 失败");
if (completionBlock) {
completionBlock(ShareTypeQQ, success);

View File

@@ -62,6 +62,16 @@
<string>ylgame</string>
</array>
</dict>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>tencent</string>
<key>CFBundleURLSchemes</key>
<array>
<string>tencent102793577</string>
</array>
</dict>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>