iOS支付宝小程序与原生交互分析
1.从 https://github.com/mpaas-demo/ios-tinyapp?spm=a2c4g.11186623.2.23.7e386fe0mar9s5 下载支付宝小程序demo,
按照说明执行
1).修改Podfile,设置基线号,支持设置为10.1.68-beta
2)、pod mpaas update --all
3)、pod update
根据提示再升级pod的mpaas版本,然后再pod update
demo能正常运行了
2.从官方文档可以看到FalconLooks库小程序需要
3.hook push方法先从进入页面的堆栈看,看不出啥
4.hook一下WKWebView的@selector(evaluateJavaScript:completionHandlerS:)
.h
#import <WebKit/WebKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface WKWebView (YYY)
@end
NS_ASSUME_NONNULL_END
.m
#import "WKWebView+YYY.h"
#import <objc/runtime.h>
typedef void (^BLOCKYYY)(id _Nullable str7 , NSError * er7) ;
@implementation WKWebView (YYY)
+(void)load{
{
Method originalMethod = class_getInstanceMethod([NSClassFromString(@"WKWebView") class], @selector(evaluateJavaScript:completionHandler:));
Method swizzledMethod = class_getInstanceMethod([self class], @selector(evaluateJavaScript:completionHandlerS:));
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
-(void)evaluateJavaScript:(NSString *)javaScriptString completionHandlerS:(void (^)(id _Nullable str7 , NSError * er7))completionHandler{
NSLog(@"小程序 %@ ",javaScriptString);
[self evaluateJavaScript:javaScriptString completionHandlerS:^(id _Nullable str, NSError *er) {
NSLog(@"小程序返回 %@ ",str);
// completionHandler(str,er);
}];
[self evaluateJavaScript:javaScriptString completionHandlerS:completionHandler];
}
@end
分类添加属性要使用关联,不能直接加
5.点击API->警告框
,看到的打印是:
2020-07-21 09:52:24.934694+0800 MPTinyAppDemo_pod[18373:5199176] 小程序 location.href
2020-07-21 09:52:35.072146+0800 MPTinyAppDemo_pod[18373:5199176] 小程序 AlipayJSBridge._handleMessageFromObjC('{\"responseId\":\"postMessage_15952963380340.17604869608612228\",\"responseData\":{\"messageEventCanceled\":false}}');
2020-07-21 09:52:38.605279+0800 MPTinyAppDemo_pod[18373:5199176] 小程序 location.href
2020-07-21 09:52:38.615518+0800 MPTinyAppDemo_pod[18373:5199176] 小程序 location.href
2020-07-21 09:52:38.616711+0800 MPTinyAppDemo_pod[18373:5199176] 小程序返回 (null)
2020-07-21 09:52:38.617399+0800 MPTinyAppDemo_pod[18373:5199176] 小程序返回 https://2020012000000001.h5app.com/index.html#page/API/alert/alert?__appxPageId=102
2020-07-21 09:52:38.620946+0800 MPTinyAppDemo_pod[18373:5199176] 小程序返回 https://2020012000000001.h5app.com/index.html#page/API/alert/alert?__appxPageId=102
2020-07-21 09:59:38.614236+0800 MPTinyAppDemo_pod[18373:5199176] 小程序 location.href
2020-07-21 09:59:39.114819+0800 MPTinyAppDemo_pod[18373:5199176] 小程序 location.href
2020-07-21 09:59:39.372248+0800 MPTinyAppDemo_pod[18373:5199176] 小程序返回 https://2020012000000001.h5app.com/index.html#page/API/alert/alert?__appxPageId=102
2020-07-21 09:59:40.035466+0800 MPTinyAppDemo_pod[18373:5199176] 小程序 AlipayJSBridge._handleMessageFromObjC('{\"callbackId\":\"objc_cb_3\",\"handlerName\":\"back\"}');
可以看到也没有什么有用信息
6.但是在上面方法打个断点,可以看到
H5JSCBridge的@selector(doCallWithItem:callBack:)这个方法
7.hook这个方法
- (void)doCallWithItem:(id)arg1 callBackS:(id)arg2;
{
NSLog(@"doCallWithItem参数%@",arg1);
[self doCallWithItem:arg1 callBackS:arg2 ];
}
并点击警告框 看其打印
2020-07-21 10:12:39.742773+0800 MPTinyAppDemo_pod[18410:5206087] doCallWithItem参数{
callbackId = "pushWindow_15952975597410.2726862088613564";
data = "{\"url\":\"#page/API/alert/alert?__appxPageId=101\",\"viewId\":3,\"launchParamsTag\":\"page/API/alert/alert\"}";
handlerName = pushWindow;
}
2020-07-21 10:12:40.268824+0800 MPTinyAppDemo_pod[18410:5206087] doCallWithItem参数{
callbackId = "postMessage_15952975602670.6360432434314175";
data = "{\"data\":\"{\\\"data\\\":{\\\"c\\\":\\\"self\\\",\\\"m\\\":\\\"invokeCallback\\\",\\\"d\\\":101,\\\"a\\\":[1,{\\\"showOptionMenu\\\":false,\\\"app_startup_type\\\":\\\"inner\\\",\\\"url\\\":\\\"https://2020012000000001.h5app.com/index.html#page/tabBar/component/index\\\",\\\"enableKeepAlive\\\":false,\\\"backgroundColor\\\":16119289,\\\"transparentTitle\\\":\\\"auto\\\",\\\"allowsBounceVertical\\\":\\\"NO\\\",\\\"version\\\":\\\"1.0.99.0\\\",\\\"enableTabBar\\\":true,\\\"backBehavior\\\":\\\"pop\\\",\\\"inPageRenderType\\\":\\\"map|video|camera|canvas|cdp|ai-camera|ad\\\",\\\"nboffline\\\":\\\"sync\\\",\\\"titleBarColor\\\":16777215,\\\"kPSDSceneInjectRequest\\\":true,\\\"sourceId\\\":\\\"\\\",\\\"enableDSL\\\":true,\\\"kPSDSessionH5Mode\\\":0,\\\"kPSDSessionPSDType\\\":0,\\\"appId\\\":\\\"2020012000000001\\\",\\\"tinyPubRes\\\":true,\\\"launchParamsTag\\\":\\\"page/tabBar/component/index\\\",\\\"defaultTitle\\
2020-07-21 10:12:41.427530+0800 MPTinyAppDemo_pod[18410:5206087] doCallWithItem参数{
callbackId = "alert_15952975614230.9276469663708761";
data = "{\"title\":\"\U4eb2\",\"message\":\"\U60a8\U672c\U6708\U7684\U8d26\U5355\U5df2\U51fa\",\"button\":\"\U6211\U77e5\U9053\U4e86\"}";
handlerName = alert;
}
这样就能看到插件名字和参数了。
上面用到了跳页的pushWindow,弹框的alert。
到这里一般开发中遇到的问题及参数打印应该就没多大问题了。
8.按照惯例doFlushMessageQueue的功能是与h5交互,将返回的数据交给不同的插件去跳页或展示
用模拟器运行一下拖到hopper看一下,
void -[H5JSCBridge doFlushMessageQueue:](void * self, void * _cmd, void * arg2) {
r14 = [arg2 retain];
objc_initWeak(&var_-40, self);
*(&var_-48 + 0xffffffffffffffd8) = __NSConcreteStackBlock;
*(&var_-48 + 0xffffffffffffffe0) = 0xc2000000;
*(&var_-48 + 0xffffffffffffffe8) = ___35-[H5JSCBridge doFlushMessageQueue:]_block_invoke;
*(&var_-48 + 0xfffffffffffffff0) = ___block_descriptor_48_e8_32s40w_e5_v8?0l;
objc_copyWeak(&var_-48, &var_-40);
rax = [r14 retain];
*(&var_-48 + 0xfffffffffffffff8) = rax;
_ExMainCall_NebulaSDK("-[H5JSCBridge doFlushMessageQueue:]", 0x0, &var_-88);
[var_-56 release];
objc_destroyWeak(&var_-48);
objc_destroyWeak(&var_-40);
[rax release];
return;
}
function ___35-[H5JSCBridge doFlushMessageQueue:]_block_invoke {
r14 = rdi;
rax = objc_loadWeakRetained(rdi + 0x28);
rbx = rax;
if (rax != 0x0) {
rdx = [NSArray class];
if ([*(r14 + 0x20) isKindOfClass:rdx] != 0x0) {
rax = [*(r14 + 0x20) copy];
var_-56 = rax;
rax = [rax count];
var_-48 = rbx;
if (rax > 0x0) {
r13 = rax;
r15 = _objc_msgSend;
r12 = 0x0;
do {
rax = (r15)(var_-56, @selector(objectAtIndex:), r12, 0x0);
rax = [rax retain];
(r15)(var_-48, @selector(doCallWithItem:callBack:), rax, 0x0);
[rax release];
r12 = r12 + 0x1;
} while (r13 != r12);
}
[var_-56 release];
rbx = var_-48;
}
}
rax = [rbx release];
return rax;
}
void -[H5JSCBridge doFlushMessageQueue:callBack:](void * self, void * _cmd, void * arg2, void * arg3) {
r15 = [arg2 retain];
r12 = [arg3 retain];
objc_initWeak(&var_-48, self);
*(&var_-56 + 0xffffffffffffffd0) = __NSConcreteStackBlock;
*(&var_-56 + 0xffffffffffffffd8) = 0xc2000000;
*(&var_-56 + 0xffffffffffffffe0) = ___44-[H5JSCBridge doFlushMessageQueue:callBack:]_block_invoke;
*(&var_-56 + 0xffffffffffffffe8) = ___block_descriptor_56_e8_32s40bs48w_e5_v8?0l;
objc_copyWeak(&var_-56, &var_-48);
rax = [r15 retain];
r14 = rax;
*(&var_-56 + 0xfffffffffffffff0) = rax;
rax = [r12 retain];
*(&var_-56 + 0xfffffffffffffff8) = rax;
_ExMainCall_NebulaSDK("-[H5JSCBridge doFlushMessageQueue:callBack:]", 0x0, &var_-104);
[var_-64 release];
[var_-72 release];
objc_destroyWeak(&var_-56);
objc_destroyWeak(&var_-48);
[rax release];
[r14 release];
return;
}
但这个不是
9.在void -[PSDJsBridge _doFlushMessageQueue:url:]打断点
看到了这个方法
MPTinyAppDemo_pod`-[PSDScriptMessageHandlerProxy userContentController:didReceiveScriptMessage:]:
这个应该就是h5直接调用原生的源方法
hook它,
#import "PSDScriptMessageHandlerProxy+YYY.h"
#import <objc/runtime.h>
@implementation PSDScriptMessageHandlerProxy (YYY)
+(void)load{
Method originalMethod = class_getInstanceMethod([self class], @selector(userContentController:didReceiveScriptMessage:));
Method swizzledMethod = class_getInstanceMethod([self class], @selector(userContentController:didReceiveScriptMessageS:));
method_exchangeImplementations(originalMethod, swizzledMethod);
}
- (void)userContentController:(nonnull WKUserContentController *)arg1 didReceiveScriptMessageS:(nonnull WKScriptMessage *)arg2;{
NSLog(@"userContentController %@ %@ %@",arg1,arg2.body,arg2.name);
[self userContentController:arg1 didReceiveScriptMessageS:arg2];
}
@end
打印数据有下面这个,应该还有间接的取值过程
2020-07-21 11:08:40.929573+0800 MPTinyAppDemo_pod[64206:6239032] userContentController <WKUserContentController: 0x600000f13600> {
msgKt = 41fa91654a13b6bca904cfcea7279bc1;
queue = "[{\"responseId\":\"objc_cb_1\",\"responseData\":{\"messageEventCanceled\":false,\"syncJsApis\":[]}}]";
type = api;
} PSDBRIDGEMESSAGEHANDLER
暂时先这样,后面遇到相关问题再完善
10.容器控制器打印创建参数
PSDScene *delegate = (PSDScene *)self.delegate;
PSDSceneParam *psdScene = [delegate createParam];
NSDictionary *dic = psdScene.expandParams;
参数中包含tinyPubRes = 1;
猜想这个参数可以判断当前打开的是小程序还是离线包。
本文地址:https://blog.csdn.net/qq_15509071/article/details/107406227