序

本文源于今天早上@清望同学遇到的一个问题。
需求
项目需求需要使用两个不同的微信appid授权,进行不同的操作。
appid1: 用于微信授权进行账号登录。
appid2: 用于微信授权进行微信取现。
问题
获取appid2授权时,可能跳转到appid1的授权页。
分析
微信授权

// 1. 注册
[WXApi registerApp:WEIXIN_APP_ID];
// 2. 请求授权
SendAuthReq *auth = [[SendAuthReq alloc] init];
auth.scope = @"snsapi_userinfo";
auth.state = @"UUID";
[WXApi sendAuthReq:auth viewController:nil delegate:self];
// 3. 处理请求结果
[WXApi handleOpenURL:url delegate:self];
以上是微信的授权流程。由于两次请求授权使用不同的key。所以每次请求之前都重新初始化。但是没有跳转到相应appid的授权。
猜测
由于是授权页没有调转到相应appid的授权页。
所以猜测<code>[WXApi registerApp:WEIXIN_APP_ID];</code>接口重新初始化,appid没有改变
验证猜测
由于请求授权<code>[WXApi sendAuthReq:auth viewController:nil delegate:self];</code> 内部最终会调用<code>UIApplication</code>的
<code>- (void)openURL:(NSURL*)url options:(NSDictionary<NSString *, id> *)options completionHandler:(void (^ __nullable)(BOOL success))completion</code>接口。
我们可以注入钩子代码查看这里的<code>url</code>值是否使用正确的appid。
[[UIApplication sharedApplication] aspect_hookSelector:@selector(openURL:options:completionHandler:) withOptions:AspectPositionBefore usingBlock:^(id aspectInfo) {
// 打印微信URL参数
NSLog(@"%@: %@", aspectInfo.instance, aspectInfo.arguments);
} error:NULL];
注入方法
- 使用runtime。这种方法需要额外手工写代码注入方法。
- 使用Aspects。使用比较简单。源码地址 https://github.com/steipete/Aspects
解决问题
确认是由于<code>[WXApi registerApp:WEIXIN_APP_ID];</code>接口重新初始化后,并没有修改相应的appid。
那么我们做相应的修改来确保重新初始化appid。
方法一:使用runtime直接修改微信内部属性值。
我没有采用这种方法。如果你做了,可以告诉我怎么做 :)
方法二:修改<code>UIApplication</code>的openURL函数调用时的url值,修改为正确的appid。
#define WEIXIN_APP_ID_1 @"微信appid1"
#define WEIXIN_APP_ID_2 @"微信appid2"
[[UIApplication sharedApplication] aspect_hookSelector:@selector(openURL:options:completionHandler:) withOptions:AspectPositionInstead usingBlock:^(id<AspectInfo> aspectInfo) {
NSLog(@"%@: %@", aspectInfo.instance, aspectInfo.arguments);
// 修改url中相应的appid参数。
NSInvocation *invocation = info.originalInvocation;
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"weixin://app/%@/auth/?scope=snsapi_userinfo&state=%@", WEIXIN_APP_ID_2,weakSelf.reqKey]];
[invocation setArgument:&url atIndex:2];
[invocation retainArguments];
[invocation invoke];
} error:NULL];
总结
- 微信sdk初始化,再次初始化不会改变相应的appid值。也没有提供反初始化接口。
- 采用钩子的方法,验证猜想。
- 使用runtime修复问题。
后续
微信SDK内部还可能存储上一次的授权信息。也需要清除。看看下午调试结果再补充吧……
网友评论
req.scope = @"snsapi_message,snsapi_userinfo,snsapi_friend,snsapi_contact"; // @"post_timeline,sns"
req.state = @"wallet";
req.openID = @"";
// [WXApi sendReq:req];
[WXApi sendAuthReq:req viewController:self delegate:nil];
[[UIApplication sharedApplication] aspect_hookSelector:@selector(openURL:options:completionHandler:) withOptions:AspectPositionBefore usingBlock:^(id<AspectInfo> aspectInfo) {
NSLog(@"%@: %@", aspectInfo.instance, aspectInfo.arguments);
// 修改url中相应的appid参数。
NSInvocation *invocation = aspectInfo.originalInvocation;
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"weixin://app/%@/auth/?scope=snsapi_userinfo&state=%@", appid,@"text"]];
[invocation setArgument:&url atIndex:2];
[invocation retainArguments];
} error:NULL];
这个方法是这么调用吗,但是不进回调方法啊
获取NSInvocation。修改参数。
NSLog(@"%@: %@", aspectInfo.instance, aspectInfo.arguments);
// 修改url中相应的appid参数。
NSInvocation *invocation = info.originalInvocation;
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"weixin://app/%@/auth/?scope=snsapi_userinfo&state=%@", WEIXIN_APP_ID_2,weakSelf.reqKey]];
[invocation setArgument:&url atIndex:2];
[invocation retainArguments];