Skip to content

Commit 9a05b65

Browse files
committed
refactor: 优化 js
1 parent 29ffca5 commit 9a05b65

File tree

7 files changed

+230
-141
lines changed

7 files changed

+230
-141
lines changed

STMScriptMessageHandler.xcodeproj/project.pbxproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10+
003BFC1725E8DFAF00B4FBB1 /* STMScriptMessageHandler_JS.m in Sources */ = {isa = PBXBuildFile; fileRef = 003BFC1625E8DFAF00B4FBB1 /* STMScriptMessageHandler_JS.m */; };
1011
00E3CA6A22B4E678005C6806 /* WKWebView+STMScriptMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E3CA6922B4E678005C6806 /* WKWebView+STMScriptMessage.m */; };
1112
B8155B712116DAA900FD0739 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B8155B702116DAA900FD0739 /* AppDelegate.m */; };
1213
B8155B772116DAA900FD0739 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B8155B752116DAA900FD0739 /* Main.storyboard */; };
@@ -20,6 +21,8 @@
2021
/* End PBXBuildFile section */
2122

2223
/* Begin PBXFileReference section */
24+
003BFC1525E8DFAF00B4FBB1 /* STMScriptMessageHandler_JS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = STMScriptMessageHandler_JS.h; sourceTree = "<group>"; };
25+
003BFC1625E8DFAF00B4FBB1 /* STMScriptMessageHandler_JS.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = STMScriptMessageHandler_JS.m; sourceTree = "<group>"; };
2326
00E3CA6822B4E678005C6806 /* WKWebView+STMScriptMessage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "WKWebView+STMScriptMessage.h"; sourceTree = "<group>"; };
2427
00E3CA6922B4E678005C6806 /* WKWebView+STMScriptMessage.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "WKWebView+STMScriptMessage.m"; sourceTree = "<group>"; };
2528
B8155B6C2116DAA900FD0739 /* STMScriptMessageHandler.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = STMScriptMessageHandler.app; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -87,6 +90,8 @@
8790
B8155B862116DB9600FD0739 /* STMScriptMessageHandler.m */,
8891
00E3CA6822B4E678005C6806 /* WKWebView+STMScriptMessage.h */,
8992
00E3CA6922B4E678005C6806 /* WKWebView+STMScriptMessage.m */,
93+
003BFC1525E8DFAF00B4FBB1 /* STMScriptMessageHandler_JS.h */,
94+
003BFC1625E8DFAF00B4FBB1 /* STMScriptMessageHandler_JS.m */,
9095
);
9196
path = Source;
9297
sourceTree = "<group>";
@@ -175,6 +180,7 @@
175180
isa = PBXSourcesBuildPhase;
176181
buildActionMask = 2147483647;
177182
files = (
183+
003BFC1725E8DFAF00B4FBB1 /* STMScriptMessageHandler_JS.m in Sources */,
178184
B8155B8E2116DB9700FD0739 /* STMScriptMessageHandler.m in Sources */,
179185
B8155B902116DB9700FD0739 /* STMViewController.m in Sources */,
180186
B8155B8F2116DB9700FD0739 /* STMWebViewController.m in Sources */,

STMScriptMessageHandler/Demo/STMViewController.m

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@
1111
static NSInteger const kRightBarItemBaseTag = 3001;
1212

1313
@interface STMViewController ()
14-
@property (nullable, nonatomic, copy) STMResponseCallback responseCallback;
14+
@property (nullable, nonatomic, strong) NSString *responseCallback;
1515
@property (nullable, nonatomic, strong) STMScriptMessageHandler *page;
1616

1717
@end
1818

1919
@interface STMViewController (Demo)
20-
- (void)setupRightBarButtonItems:(NSArray<NSDictionary *> *)items callback:(STMResponseCallback)responseCallback;
20+
- (void)setupRightBarButtonItems:(NSDictionary *)data;
2121
@end
2222

2323
@implementation STMViewController
@@ -59,8 +59,9 @@ - (void)prepareScriptMessageHandler {
5959
// register a message handler named `Page`, so the js should call your method that the message handler registered use App.Page.callMethod...
6060
self.page = [self.webView stm_addScriptMessageHandlerUseName:@"Page"];
6161

62-
[self.page registerMethod:@"setButtons" reuseHandler:YES handler:^(id data, STMResponseCallback responseCallback) {
63-
[self setupRightBarButtonItems:data callback:responseCallback];
62+
[self.page registerMethod:@"setButtons" handler:^(id data, STMResponseCallback responseCallback) {
63+
[self setupRightBarButtonItems:data];
64+
responseCallback(@(YES));
6465
}];
6566
}
6667

@@ -80,13 +81,14 @@ - (void)test {
8081

8182
@implementation STMViewController (Demo)
8283

83-
- (void)setupRightBarButtonItems:(NSArray<NSDictionary *> *)items callback:(STMResponseCallback)responseCallback {
84-
self.responseCallback = responseCallback;
84+
- (void)setupRightBarButtonItems:(NSDictionary *)data {
85+
self.responseCallback = data[@"callback"];
86+
NSArray<NSDictionary *> *items = data[@"data"];
8587
[self _setupNavigationBarButtonItems:items];
8688
}
8789

8890
- (void)_handleRightBarButtonItemAction:(UIBarButtonItem *)sender {
89-
self.responseCallback(@(sender.tag - kRightBarItemBaseTag));
91+
[self.page callMethod:self.responseCallback parameters:@(sender.tag - kRightBarItemBaseTag) responseHandler:nil];
9092
}
9193

9294
- (void)_setupNavigationBarButtonItems:(NSArray<NSDictionary *> *)items {

STMScriptMessageHandler/Demo/index.html

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
var uniqueId = 1;
1212
var testCallback;
1313

14+
var JSBridge = window.Bridge;
15+
var JSPage = window.Page;
16+
1417
function log(message, data) {
1518
var log = document.getElementById('log')
1619
var el = document.createElement('div')
@@ -19,17 +22,17 @@
1922
if (log.children.length) { log.insertBefore(el, log.children[0]) }
2023
else { log.appendChild(el) }
2124
}
25+
2226
function setRightButtons() {
2327
var buttons = [{ "title": '按钮0' }, { "title": '按钮1' }];
2428
log('JS calling native method "setButtons"', buttons);
25-
App.Page.callMethod('setButtons', buttons, function (index) {
26-
var response = '点击了按钮' + index;
27-
log('JS got native `setButtons` response', response);
29+
JSPage.callHandler('setButtons', {'callback': 'handleTapButtonAction', 'data': buttons}, function (result) {
30+
log('JS got native `setButtons` response', result);
2831
});
2932
}
3033

3134
function nslog(data) {
32-
App.Bridge.callMethod('nslog', data, function (data) {
35+
JSBridge.callHandler('nslog', data, function (data) {
3336
log('JS got native `nslog` response', data);
3437
});
3538
}
@@ -43,20 +46,25 @@
4346
}
4447
}
4548

46-
App.Bridge.callMethod('testNativeMethod', { foo: 'foo', bar: 'bar' }, function (data) {
49+
JSBridge.callHandler('testNativeMethod', { foo: 'foo', bar: 'bar' }, function (data) {
4750
log('JS got native `testNativeMethod` response', data);
4851
});
4952

50-
App.Bridge.registerMethod('log', function (data, callback) {
53+
JSBridge.registerHandler('log', function (data, callback) {
5154
var message = data;
5255
log('Native calling js method `log`', message);
5356
callback({ key: 'from js', value: data });
5457
});
5558

56-
App.Bridge.registerMethod('test', function(data, callback) {
59+
JSBridge.registerHandler('test', function(data, callback) {
5760
log('save callback');
5861
testCallback = callback;
59-
}, true);
62+
});
63+
64+
JSPage.registerHandler('handleTapButtonAction', function(index) {
65+
var response = '点击了按钮' + index;
66+
log('Native calling js method `handleTapButtonAction`', response);
67+
});
6068

6169
</script>
6270
</head><body>

STMScriptMessageHandler/Source/STMScriptMessageHandler.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,9 @@ typedef void (^STMHandler)(id data, STMResponseCallback _Nullable responseCallba
2424
- (void)prepareJsScript NS_REQUIRES_SUPER;
2525

2626
- (void)registerMethod:(NSString *)methodName handler:(STMHandler)handler;
27-
- (void)registerMethod:(NSString *)methodName reuseHandler:(BOOL)reuse handler:(STMHandler)handler;
28-
- (void)callMethod:(NSString *)methodName parameters:(NSDictionary *)parameters responseHandler:(STMResponseCallback)handler;
27+
- (void)removeMethod:(NSString *)methodName;
28+
29+
- (void)callMethod:(NSString *)methodName parameters:(id)parameters responseHandler:(nullable STMResponseCallback)handler;
2930

3031
@end
3132

STMScriptMessageHandler/Source/STMScriptMessageHandler.m

Lines changed: 70 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//
77

88
#import "STMScriptMessageHandler.h"
9+
#import "STMScriptMessageHandler_JS.h"
910

1011
#define STM_JS_FUNC(x, ...) [NSString stringWithFormat:@#x ,##__VA_ARGS__]
1112
#define WEAK_SELF __weak typeof(self) __weak_self__ = self
@@ -16,10 +17,11 @@
1617
static NSString * const kSTMMethodHandlerReuseKey = @"kSTMMethodHandlerReuseKey";
1718
static NSString * const kSTMMethodHandlerIMPKey = @"kSTMMethodHandlerIMPKey";
1819

19-
static NSString * const kSTMMessageParameterNameKey = @"name";
20-
static NSString * const kSTMMessageParameterInfoKey = @"info";
20+
static NSString * const kSTMMessageParameterNameKey = @"handlerName";
21+
static NSString * const kSTMMessageParameterInfoKey = @"data";
22+
static NSString * const kSTMMessageParameterResponseKey = @"responseData";
2123
static NSString * const kSTMMessageParameterCallbackIdKey = @"callbackId";
22-
static NSString * const kSTMMessageParameterReuseKey = @"reuse";
24+
static NSString * const kSTMMessageParameterResponseIdKey = @"responseId";
2325

2426
static int gSTMCallbackUniqueId = 1;
2527

@@ -46,124 +48,84 @@ - (instancetype)initWithScriptMessageHandlerName:(NSString *)handlerName forWebV
4648
}
4749

4850
- (void)prepareJsScript {
49-
[self _addJS1];
50-
[self _addJS2];
51-
[self _addJS3];
52-
WEAK_SELF;
53-
[self registerMethod:kSTMNativeCallback handler:^(NSDictionary * _Nonnull data, STMResponseCallback _Nullable responseCallback) {
54-
STRONG_SELF;
55-
NSDictionary *info = data[kSTMMessageParameterInfoKey];
56-
NSString *callbackId = data[kSTMMessageParameterCallbackIdKey] ?: @"";
57-
BOOL reuse = [data[kSTMMessageParameterReuseKey] boolValue];
58-
STMResponseCallback jsResponse = self.jsResponseHandlers[callbackId];
59-
!jsResponse ?: jsResponse(info);
60-
if (!reuse) {
61-
[self.jsResponseHandlers removeObjectForKey:callbackId];
62-
}
63-
}];
51+
NSString *js = STMScriptMessageHandler_js(self.handlerName);
52+
// [self _evaluateJavaScript:js];
53+
[self _addJSScript:js forMainFrameOnly:NO];
6454
}
6555

66-
- (void)registerMethod:(NSString *)methodName handler:(STMHandler)handler {
67-
[self registerMethod:methodName reuseHandler:NO handler:handler];
68-
}
69-
70-
- (void)registerMethod:(NSString *)methodName reuseHandler:(BOOL)reuse handler:(nonnull STMHandler)handler {
56+
- (void)registerMethod:(NSString *)methodName handler:(nonnull STMHandler)handler {
7157
if (!methodName || !handler) { return; }
7258
if (handler) {
73-
self.methodHandlers[methodName] = @{kSTMMethodHandlerReuseKey : @(reuse),
74-
kSTMMethodHandlerIMPKey : handler};
59+
self.methodHandlers[methodName] = handler;
7560
}
7661
}
7762

78-
- (void)callMethod:(NSString *)methodName parameters:(NSDictionary *)parameters responseHandler:(STMResponseCallback)handler {
63+
- (void)removeMethod:(NSString *)methodName {
64+
if (!methodName) { return; }
65+
[self.methodHandlers removeObjectForKey:methodName];
66+
}
67+
68+
- (void)callMethod:(NSString *)methodName parameters:(id)parameters responseHandler:(STMResponseCallback)handler {
7969
if (!methodName) { return; }
80-
NSString *callbackId = @"";
70+
NSMutableDictionary *message = [NSMutableDictionary dictionary];
71+
if (parameters) {
72+
message[kSTMMessageParameterInfoKey] = parameters;
73+
}
74+
8175
if (handler) {
82-
callbackId = [NSString stringWithFormat:@"cb_%d_%.0f", gSTMCallbackUniqueId++, [NSDate timeIntervalSinceReferenceDate] * 1000];
76+
NSString *callbackId = [NSString stringWithFormat:@"cb_%d_%.0f", gSTMCallbackUniqueId++, [NSDate timeIntervalSinceReferenceDate] * 1000];
8377
self.jsResponseHandlers[callbackId] = handler;
78+
message[kSTMMessageParameterCallbackIdKey] = callbackId;
8479
}
85-
NSString *formatParameter = [self _formatParameters:@{@"parameters": parameters}];
86-
NSString *js = STM_JS_FUNC(%@.%@.nativeCall('%@',JSON.parse('%@').parameters,'%@'), kSTMApp, self.handlerName, methodName, formatParameter, callbackId);
87-
[self _evaluateJavaScript:js];
88-
[self _debug:@"native call js's method" method:methodName parameters:parameters];
89-
}
90-
91-
#pragma mark - Private
9280

93-
- (void)_response:(NSString *)methodName callbackId:(NSString *)callbackId parameter:(nullable id)parameter deleteCallback:(BOOL)delete {
94-
NSString *formatParameter = [self _formatParameters:@{@"responseData": parameter}];
95-
callbackId = callbackId ?: @"";
96-
NSString *js = STM_JS_FUNC(
97-
var callback = %@.%@.callback['%@'];
98-
if (callback) { callback(JSON.parse('%@').responseData); if (%d) { delete %@.%@.callback.%@ }}
99-
, kSTMApp, self.handlerName, callbackId, formatParameter, delete, kSTMApp, self.handlerName, callbackId
100-
);
101-
[self _evaluateJavaScript:js];
81+
message[kSTMMessageParameterNameKey] = methodName;
82+
[self _dispatchMessage:message];
10283
}
10384

104-
- (void)_addJS1 {
105-
NSString *jsScript = STM_JS_FUNC(var %@ = window.webkit.messageHandlers;, kSTMApp);
106-
[self _addJSScript:jsScript forMainFrameOnly:YES];
107-
}
108-
109-
- (void)_addJS2 {
110-
NSString *jsScript = STM_JS_FUNC(
111-
%@.%@.registerMethod = function(methodName, methodHandler, reuse) {
112-
if (!%@.%@.methods) {
113-
%@.%@.methods = {};
114-
}
115-
var handlerInfo = {};
116-
handlerInfo['imp'] = methodHandler;
117-
handlerInfo['reuse'] = reuse;
118-
%@.%@.methods[methodName] = handlerInfo;
119-
}
120-
, kSTMApp, self.handlerName,
121-
kSTMApp, self.handlerName,
122-
kSTMApp, self.handlerName,
123-
kSTMApp, self.handlerName
124-
);
125-
[self _addJSScript:jsScript forMainFrameOnly:YES];
126-
127-
NSString *js = STM_JS_FUNC(
128-
var callbackUniqueId = 1;
129-
if (!%@.%@.callback) {
130-
%@.%@.callback = {};
131-
};
132-
%@.%@.callMethod = function(name, info, callback) {
133-
var message = {};
134-
message['name'] = name;
135-
message['info'] = info;
136-
if (callback) {
137-
var callbackId = 'cb_'+(callbackUniqueId++)+'_'+new Date().getTime();
138-
%@.%@.callback[callbackId] = callback;
139-
message['callbackId'] = callbackId;
140-
}
141-
%@.%@.postMessage(message);
142-
};
143-
, kSTMApp, self.handlerName,
144-
kSTMApp, self.handlerName,
145-
kSTMApp, self.handlerName,
146-
kSTMApp, self.handlerName,
147-
kSTMApp, self.handlerName
148-
);
149-
[self _addJSScript:js forMainFrameOnly:YES];
150-
}
85+
#pragma mark - Private
15186

152-
- (void)_addJS3 {
153-
NSString *jsScript = STM_JS_FUNC(
154-
%@.%@.nativeCall = function(methodName, info, callbackId) {
155-
var handlerInfo = %@.%@.methods[methodName];
156-
var reuse = handlerInfo['reuse'];
157-
var handler = handlerInfo['imp'];
158-
handler(info, function(data){
159-
%@.%@.postMessage({name:'%@',info:{name:methodName,info:data,callbackId:callbackId,reuse:reuse}});
160-
});
161-
}
162-
, kSTMApp, self.handlerName,
163-
kSTMApp, self.handlerName,
164-
kSTMApp, self.handlerName, kSTMNativeCallback
165-
);
166-
[self _addJSScript:jsScript forMainFrameOnly:YES];
87+
//给 js 端发送消息
88+
- (void)_dispatchMessage:(NSDictionary *)message {
89+
NSString *messageJSON = [self _formatParameters:message];
90+
NSString* javascriptCommand = [NSString stringWithFormat:@"%@._handleMessageFromObjC('%@');", self.handlerName, messageJSON];
91+
[self _evaluateJavaScript:javascriptCommand];
92+
}
93+
94+
//处理收到的 js 端消息
95+
- (void)_flushReceivedMessage:(NSDictionary *)message {
96+
if (![message isKindOfClass:NSDictionary.class]) {
97+
return;
98+
}
99+
100+
NSString *responseId = message[kSTMMessageParameterResponseIdKey];
101+
if (responseId) {
102+
STMResponseCallback responseCallback = self.jsResponseHandlers[responseId];
103+
!responseCallback ?: responseCallback(message[kSTMMessageParameterResponseKey]);
104+
[self.jsResponseHandlers removeObjectForKey:responseId];
105+
} else {
106+
STMResponseCallback responseCallback; {
107+
NSString *callbackId = message[kSTMMessageParameterCallbackIdKey];
108+
if (callbackId) {
109+
responseCallback = ^(id responseData){
110+
if (!responseData) {
111+
responseData = [NSNull null];
112+
}
113+
[self _dispatchMessage:@{
114+
kSTMMessageParameterResponseIdKey: callbackId,
115+
kSTMMessageParameterResponseKey: responseData,
116+
}];
117+
};
118+
} else {
119+
responseCallback = ^(id responseData){
120+
};
121+
}
122+
}
123+
STMHandler handler = self.methodHandlers[message[kSTMMessageParameterNameKey]];
124+
if (!handler) {
125+
return;
126+
}
127+
handler(message[kSTMMessageParameterInfoKey], responseCallback);
128+
}
167129
}
168130

169131
#pragma mark -
@@ -183,6 +145,7 @@ - (void)_evaluateJavaScript:(NSString *)javaScriptString {
183145
[self.webView evaluateJavaScript:javaScriptString completionHandler:^(id _Nullable info, NSError * _Nullable error) {
184146
__strong typeof(__weak_self__) self = __weak_self__;
185147
if (error) {
148+
NSLog(@"Error: %@", error);
186149
[self.webView reload];
187150
}
188151
}];
@@ -226,24 +189,7 @@ - (void)_debug:(NSString *)name method:(NSString *)method parameters:(NSDictiona
226189

227190
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
228191
if (![message.name isEqualToString:self.handlerName]) { return; }
229-
NSString *method = message.body[kSTMMessageParameterNameKey];
230-
NSDictionary *parameter = message.body[kSTMMessageParameterInfoKey];
231-
NSString *callbackId = message.body[kSTMMessageParameterCallbackIdKey];
232-
NSDictionary *handlerInfo = self.methodHandlers[method];
233-
STMHandler handler = handlerInfo[kSTMMethodHandlerIMPKey];
234-
BOOL reuseHandler = [handlerInfo[kSTMMethodHandlerReuseKey] boolValue];
235-
if ([method isEqualToString:kSTMNativeCallback]) {
236-
handler(parameter, nil);
237-
[self _debug:@"native receive js's response" method:parameter[kSTMMessageParameterNameKey] parameters:parameter[kSTMMessageParameterInfoKey]];
238-
} else {
239-
[self _debug:@"js call native's method" method:method parameters:parameter];
240-
WEAK_SELF;
241-
handler(parameter, ^(id info) {
242-
STRONG_SELF;
243-
[self _response:method callbackId:callbackId parameter:info deleteCallback:!reuseHandler];
244-
[self _debug:@"js receive native's response" method:method parameters:info];
245-
});
246-
}
192+
[self _flushReceivedMessage:message.body];
247193
}
248194

249195
#pragma mark - setter & getter

0 commit comments

Comments
 (0)