// // FINExtensionHelper.m // finclip_custom_demo // // Created by Haley on 2020/12/3. // #import "FINExtensionHelper.h" #import #import #import #import @interface FINExtensionHelper () // 支付时,支付的回调是异步的,故这里将小程序的回调持有,在适当的时机调用(用户可根据自己的场景自行实现自己调用的逻辑) @property (nonatomic, copy) FATExtensionApiCallback callback; @end static FINExtensionHelper *instance = nil; @implementation FINExtensionHelper + (instancetype)sharedHelper { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ instance = [[FINExtensionHelper alloc] init]; }); return instance; } + (instancetype)allocWithZone:(struct _NSZone *)zone { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ instance = [super allocWithZone:zone]; }); return instance; } - (id)copy { return instance; } // 注入自定义api - (void)registerCustomApis { [[FATClient sharedClient] registerExtensionApi:@"onNative" handler:^(FATAppletInfo *appletInfo, id param, FATExtensionApiCallback callback) { NSString *inputText = @"床前明月光,疑是地上霜。举头望明月,低头思故乡。"; callback(FATExtensionCodeSuccess, @{@"text":inputText}); }]; [[FATClient sharedClient] fat_registerWebApi:@"user_define_native" handler:^(FATAppletInfo *appletInfo, id param, FATExtensionApiCallback callback) { NSString *inputText = @"鹅鹅鹅,曲项向天歌,白毛浮绿水,红掌拨清波。"; callback(FATExtensionCodeSuccess, @{@"text":inputText}); }]; // 注入获取用户信息 [[FATClient sharedClient] registerExtensionApi:@"getUserProfile" handler:^(FATAppletInfo *appletInfo, id param, FATExtensionApiCallback callback) { NSDictionary *userInfo = @{@"nickName":@"张三",@"avatarUrl":@"",@"gender":@1,@"country":@"中国",@"province":@"广东省",@"city":@"深圳",@"language":@"zh_CN"}; NSDictionary *resDic = @{@"userInfo":userInfo}; callback(FATExtensionCodeSuccess,resDic); }]; // 注入登录方法 [[FATClient sharedClient] registerExtensionApi:@"login" handler:^(FATAppletInfo *appletInfo, id param, FATExtensionApiCallback callback) { // 处理小程序登录逻辑后,调用小程序回调 // 登录成功回调示例 NSString *wxid = appletInfo.wechatLoginInfo[@"wechatOriginId"]; NSString *path = appletInfo.wechatLoginInfo[@"profileUrl"]; BOOL canWXLogin = [WXApi isWXAppInstalled] && [wxid length] > 0 && [path length] > 0; if (canWXLogin) { self.callback = callback; WXLaunchMiniProgramReq *req = [WXLaunchMiniProgramReq object]; req.userName = wxid; req.path = path; req.miniProgramType = WXMiniProgramTypeRelease; [WXApi sendReq:req completion:^(BOOL success) { NSLog(@"打开微信:%d", success); }]; } else { callback(FATExtensionCodeSuccess,@{@"desc":@"登录成功"}); } }]; // 注入微信支付方法 __weak typeof(self) weakSelf = self; [[FATClient sharedClient] registerExtensionApi:@"requestPayment" handler:^(FATAppletInfo *appletInfo, id param, FATExtensionApiCallback callback) { // 支付有两种方式实现: // 1.利用app实现支付,结果通过回调通告小程序 [weakSelf getTestPayment:callback]; // 2.使用微信小程序实现支付 // [weakSelf wechatMiniProgramPayment:appletInfo param:param callback:callback]; }]; } #pragma mark - WXPay // 模拟向服务请求支付订单 - (void)getTestPayment:(FATExtensionApiCallback)callback { // 以下支持示例代码,演示自行实现的过程 NSString *urlString = @"https://finclip-testing.finogeeks.club/mop/wechat-auth/api/order"; NSURL *url = [NSURL URLWithString:urlString]; NSMutableURLRequest *requset = [NSMutableURLRequest requestWithURL:url]; requset.HTTPMethod = @"POST"; __weak typeof(self) weakSelf = self; NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:requset completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; if (httpResponse.statusCode == 200) { NSString *appId = @"wx85663af68a0cbbc8"; NSString *partnerId = @"1600932850"; NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil]; NSString *prepayId = dict[@"data"][@"prepay_id"]; NSString *nonceStr = @"5K8264ILTKCH16CQ2502SI8ZNMTM67VS"; // 随机字符串,这里就不模拟了 UInt32 timeStamp = [[NSDate date] timeIntervalSince1970]; NSString *text = [NSString stringWithFormat:@"%@\n%ld\n%@\n%@\n", appId, (long)timeStamp, nonceStr, prepayId]; NSString *sign = [weakSelf sha256:text]; PayReq *request = [[PayReq alloc] init]; request.partnerId = partnerId; request.prepayId = prepayId; request.package = @"Sign=WXPay"; request.nonceStr = nonceStr; request.timeStamp = timeStamp; request.sign= sign; dispatch_async(dispatch_get_main_queue(), ^{ [WXApi sendReq:request completion:^(BOOL success) { if (success) { weakSelf.callback = callback; } else { callback(FATExtensionCodeFailure, nil); } }]; }); return; } callback(FATExtensionCodeFailure, nil); }]; [task resume]; } - (void)wechatMiniProgramPayment:(FATAppletInfo *)appletInfo param:(NSDictionary *)param callback:(FATExtensionApiCallback)callback { NSDictionary *info = appletInfo.wechatLoginInfo; NSString *wxid = appletInfo.wechatLoginInfo[@"wechatOriginId"]; NSString *path = appletInfo.wechatLoginInfo[@"paymentUrl"]; if (wxid.length == 0 || path.length == 0) { callback(FATExtensionCodeFailure, @{@"desc":@"微信小程序关联信息异常"}); return; } NSDictionary *dataDic = param; NSString *payString = [NSString stringWithFormat:@"?appId=%@&nonceStr=%@&package=%@&paySign=%@&signType=%@&timeStamp=%@&type=%@", dataDic[@"appId"], dataDic[@"nonceStr"], dataDic[@"package"], dataDic[@"paySign"], dataDic[@"signType"], dataDic[@"timeStamp"], dataDic[@"type"]]; // 需要appDelegate 里注册微信开放SDK。 WXLaunchMiniProgramReq *launchMiniProgramReq = [WXLaunchMiniProgramReq object]; launchMiniProgramReq.userName = wxid; launchMiniProgramReq.path = [NSString stringWithFormat:@"%@%@", wxid, payString]; if (appletInfo.appletVersionType == FATAppletVersionTypeRelease) { launchMiniProgramReq.miniProgramType = WXMiniProgramTypeRelease; //正式版 } else if (appletInfo.appletVersionType == FATAppletVersionTypeTrial) { launchMiniProgramReq.miniProgramType = WXMiniProgramTypePreview; //体验版 } else { launchMiniProgramReq.miniProgramType = WXMiniProgramTypeTest; //开发版 } [WXApi sendReq:launchMiniProgramReq completion:^(BOOL success) { NSLog(@"打开微信:%d", success); if (success) { callback(FATExtensionCodeSuccess, @{@"desc":@"支付成功"}); return; } callback(FATExtensionCodeFailure, @{@"desc":@"支付失败"}); }]; } // 签名加密(正常是放在后台处理,由上面的请求接口返回 - (NSString *)sha256:(NSString *)shaStr { NSData *data = [shaStr dataUsingEncoding:NSUTF8StringEncoding]; uint8_t digest[CC_SHA256_DIGEST_LENGTH]; CC_SHA256(data.bytes, (CC_LONG)data.length, digest); NSData *adata = [[NSData alloc] initWithBytes:digest length:CC_SHA256_DIGEST_LENGTH]; adata = [adata base64EncodedDataWithOptions:0]; NSString *ret = [[NSString alloc] initWithData:adata encoding:NSUTF8StringEncoding]; return ret; } #pragma mark - WXApiDelegate //发起支付请求回调 - (void)onReq:(BaseReq *)req { } //微信结果回调 - (void)onResp:(BaseResp *)resp { FATExtensionCode code = FATExtensionCodeSuccess; if (resp.errCode != WXSuccess) { code = FATExtensionCodeFailure; } if ([resp isKindOfClass:[PayResp class]]) {//支付 self.callback(code, nil); } else if ([resp isKindOfClass:[WXLaunchMiniProgramResp class]]) {//打开小程序 NSString *extMsg = ((WXLaunchMiniProgramResp *)resp).extMsg; if (extMsg.length <= 0) { self.callback(FATExtensionCodeFailure, nil); } else { self.callback(code, [self dictionaryWithJsonString:extMsg]); } } } - (NSDictionary *)dictionaryWithJsonString:(NSString *)jsonString { if (jsonString == nil) return nil; NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding]; NSError *err; NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&err]; if(err) { NSLog(@"json解析失败:%@",err); return nil; } return dic; } @end