JSBridge实现示例
前言
参考来源
前人栽树,后台乘凉,本文参考了以下来源
楔子
本文介绍JSBridge的完整实现,包括JS部分,Android原生,iOS原生部分
JS实现部分
说明
这是一份剔除了业务之后的JSbridge实现代码(JS部分)。JS实现代码就一套
实现
实现代码如下
(function() {
(function() {
var hasOwnProperty = Object.prototype.hasOwnProperty;
var JSBridge = window.JSBridge || (window.JSBridge = {});
//jsbridge协议定义的名称
var CUSTOM_PROTOCOL_SCHEME = 'CustomJSBridge';
//最外层的api名称
var API_Name = 'namespace_bridge';
//进行url scheme传值的iframe
var messagingIframe = document.createElement('iframe');
messagingIframe.style.display = 'none';
messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + API_Name;
document.documentElement.appendChild(messagingIframe);
//定义的回调函数集合,在原生调用完对应的方法后,会执行对应的回调函数id
var responseCallbacks = {};
//唯一id,用来确保每一个回调函数的唯一性
var uniqueId = 1;
//本地注册的方法集合,原生只能调用本地注册的方法,否则会提示错误
var messageHandlers = {};
//当原生调用H5注册的方法时,通过回调来调用(也就是变为了异步执行,加强安全性)
var dispatchMessagesWithTimeoutSafety = true;
//本地运行中的方法队列
var sendMessageQueue = [];
//实际暴露给原生调用的对象
var Inner = {
/**
* @description 注册本地JS方法通过JSBridge给原生调用
* 我们规定,原生必须通过JSBridge来调用H5的方法
* 注意,这里一般对本地函数有一些要求,要求第一个参数是data,第二个参数是callback
* @param {String} handlerName 方法名
* @param {Function} handler 对应的方法
*/
registerHandler: function(handlerName, handler) {
messageHandlers[handlerName] = handler;
},
/**
* @description 调用原生开放的方法
* @param {String} handlerName 方法名
* @param {JSON} data 参数
* @param {Function} callback 回调函数
*/
callHandler: function(handlerName, data, callback) {
//如果没有 data
if(arguments.length == 3 && typeof data == 'function') {
callback = data;
data = null;
}
_doSend({
handlerName: handlerName,
data: data
}, callback);
},
/**
* iOS专用
* @description 当本地调用了callHandler之后,实际是调用了通用的scheme,通知原生
* 然后原生通过调用这个方法来获知当前正在调用的方法队列
*/
_fetchQueue: function() {
var messageQueueString = JSON.stringify(sendMessageQueue);
sendMessageQueue = [];
return messageQueueString;
},
/**
* @description 原生调用H5页面注册的方法,或者调用回调方法
* @param {String} messageJSON 对应的方法的详情,需要手动转为json
*/
_handleMessageFromNative: function(messageJSON) {
setTimeout(_doDispatchMessageFromNative);
/**
* @description 处理原生过来的方法
*/
function _doDispatchMessageFromNative() {
var message;
try {
message = JSON.parse(messageJSON);
} catch(e) {
//TODO handle the exception
console.error("原生调用H5方法出错,传入参数错误");
return;
}
//回调函数
var responseCallback;
if(message.responseId) {
//这里规定,原生执行方法完毕后准备通知h5执行回调时,回调函数id是responseId
responseCallback = responseCallbacks[message.responseId];
if(!responseCallback) {
return;
}
//执行本地的回调函数
responseCallback(message.responseData);
delete responseCallbacks[message.responseId];
} else {
//否则,代表原生主动执行h5本地的函数
if(message.callbackId) {
//先判断是否需要本地H5执行回调函数
//如果需要本地函数执行回调通知原生,那么在本地注册回调函数,然后再调用原生
//回调数据有h5函数执行完毕后传入
var callbackResponseId = message.callbackId;
responseCallback = function(responseData) {
//默认是调用EJS api上面的函数
//然后接下来原生知道scheme被调用后主动获取这个信息
//所以原生这时候应该会进行判断,判断对于函数是否成功执行,并接收数据
//这时候通讯完毕(由于h5不会对回调添加回调,所以接下来没有通信了)
_doSend({
handlerName: message.handlerName,
responseId: callbackResponseId,
responseData: responseData
});
};
}
//从本地注册的函数中获取
var handler = messageHandlers[message.handlerName];
if(!handler) {
//本地没有注册这个函数
} else {
//执行本地函数,按照要求传入数据和回调
handler(message.data, responseCallback);
}
}
}
}
};
/**
* @description JS调用原生方法前,会先send到这里进行处理
* @param {JSON} message 调用的方法详情,包括方法名,参数
* @param {Function} responseCallback 调用完方法后的回调
*/
function _doSend(message, responseCallback) {
if(responseCallback) {
//取到一个唯一的callbackid
var callbackId = Util.getCallbackId();
//回调函数添加到集合中
responseCallbacks[callbackId] = responseCallback;
//方法的详情添加回调函数的关键标识
message['callbackId'] = callbackId;
}
var uri;
//android中,可以通过onJsPrompt或者截取Url访问都行
var ua = navigator.userAgent;
if(ua.match(/(iPhone\sOS)\s([\d_]+)/)||ua.match(/(iPad).*OS\s([\d_]+)/)) {
//ios中,通过截取客户端url访问
//因为ios可以不暴露scheme,而是由原生手动获取
//正在调用的方法详情添加进入消息队列中,原生会主动获取
sendMessageQueue.push(message);
uri = Util.getUri();
}else{
//android中兼容处理,将所有的参数一起拼接到url中
uri = Util.getUri(message);
}
//获取 触发方法的url scheme
//采用iframe跳转scheme的方法
messagingIframe.src = uri;
}
var Util = {
getCallbackId: function() {
//如果无法解析端口,可以换为Math.floor(Math.random() * (1 << 30));
return 'cb_' + (uniqueId++) + '_' + new Date().getTime();
},
//获取url scheme
//第二个参数是兼容android中的做法
//android中由于原生不能获取JS函数的返回值,所以得通过协议传输
getUri: function(message) {
var uri = CUSTOM_PROTOCOL_SCHEME + '://' + API_Name;
if(message) {
//回调id作为端口存在
var callbackId, method, params;
if(message.callbackId) {
//第一种:h5主动调用原生
callbackId = message.callbackId;
method = message.handlerName;
params = message.data;
} else if(message.responseId) {
//第二种:原生调用h5后,h5回调
//这种情况下需要原生自行分析传过去的port是否是它定义的回调
callbackId = message.responseId;
method = message.handlerName;
params = message.responseData;
}
//参数转为字符串
params = this.getParam(params);
//uri 补充
uri += ':' + callbackId + '/' + method + '?' + params;
}
return uri;
},
getParam: function(obj) {
if(obj && typeof obj === 'object') {
return JSON.stringify(obj);
} else {
return obj || '';
}
}
};
for(var key in Inner) {
if(!hasOwnProperty.call(JSBridge, key)) {
JSBridge[key] = Inner[key];
}
}
})();
//注册一个测试函数
JSBridge.registerHandler('testH5Func', function(data, callback) {
alert('测试函数接收到数据:' + JSON.stringify(data));
callback && callback('测试回传数据...');
});
/*
***************************API********************************************
* 开放给外界调用的api
* */
window.jsapi = {};
/**
***app 模块
* 一些特殊操作
*/
jsapi.app = {
/**
* @description 测试函数
*/
testNativeFunc: function() {
//调用一个测试函数
JSBridge.callHandler('testNativeFunc', {}, function(res) {
callback && callback(res);
});
}
};
})();
Android实现部分
说明
这是Android原生中配套的JSBridge实现代码。Android的实现相对比JS复杂,包括多个部分
JSBridge类实现
实现代码如下
public class JSBridge {
private static Map<String, HashMap<String, Method>> exposedMethods = new HashMap<>();
//原生注册API方法
public static void register(String exposedName, Class<? extends IBridge> clazz) {
if (!exposedMethods.containsKey(exposedName)) {
try {
exposedMethods.put(exposedName, getAllMethod(clazz));
} catch (Exception e) {
e.printStackTrace();
}
}
}
//得到所有的注册方法
private static HashMap<String, Method> getAllMethod(Class injectedCls) throws Exception {
HashMap<String, Method> mMethodsMap = new HashMap<>();
Method[] methods = injectedCls.getDeclaredMethods();
for (Method method : methods) {
String name;
if (method.getModifiers() != (Modifier.PUBLIC | Modifier.STATIC) || (name = method.getName()) == null) {
continue;
}
Class[] parameters = method.getParameterTypes();
if (null != parameters && parameters.length == 4) {
if (parameters[0] == BaseWebLoader.class && parameters[1] == WebView.class && parameters[2] == JSONObject.class && parameters[3] == Callback.class) {
mMethodsMap.put(name, method);
}
}
}
return mMethodsMap;
}
//调用Hava中的方法
//其中BaseWebLoader是JSBridge的webview容器(二次封装)
//执行完方法后,如果又回到,自动就会调用
public static String callJava(BaseWebLoader webLoader,WebView webView, String uriString) {
String methodName = "";
String className = "";
String param = "{}";
String port = "";
if (!TextUtils.isEmpty(uriString) && uriString.startsWith("EpointJSBridge")) {
Uri uri = Uri.parse(uriString);
className = uri.getHost();
param = uri.getQuery();
port = uri.getPort() + "";
String path = uri.getPath();
if (!TextUtils.isEmpty(path)) {
methodName = path.replace("/", "");
}
}
if (exposedMethods.containsKey(className)) {
HashMap<String, Method> methodHashMap = exposedMethods.get(className);
if (methodHashMap != null && methodHashMap.size() != 0 && methodHashMap.containsKey(methodName)) {
Method method = methodHashMap.get(methodName);
if (method != null) {
try {
method.invoke(null,webLoader, webView, new JSONObject(param), new Callback(webView, port));
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
return null;
}
}
这个类的作用是原生定义一些暴露的api
Callback类实现
实现代码如下
public class Callback {
private static Handler mHandler = new Handler(Looper.getMainLooper());
private static final String CALLBACK_JS_FORMAT = "javascript:JSBridge._handleMessageFromNative(%s);";
private String mPort;
private WeakReference<WebView> mWebViewRef;
public Callback(WebView view, String port) {
mWebViewRef = new WeakReference<>(view);
mPort = port;
}
public void apply(JSONObject jsonObject) throws JSONException {
JSONObject object = new JSONObject();
object.put("responseId", mPort);
object.putOpt("responseData", jsonObject);
final String execJs = String.format(CALLBACK_JS_FORMAT, String.valueOf(object));
//如果activity已经关闭则不回调
if (mWebViewRef != null && mWebViewRef.get() != null && !((BaseWebLoader) mWebViewRef.get().getContext()).getActivity().isFinishing()) {
mHandler.post(new Runnable() {
@Override
public void run() {
mWebViewRef.get().loadUrl(execJs);
}
});
}
}
}
这个类的作用是,定义原生中的回调函数
Webview容器关键代码实现
实现代码如下
注册api方法
//定义api集合
JSBridge.register("namespace_bridge",BridgeImpl.class);
捕获url scheme并执行方法的代码
public boolean shouldOverrideUrlLoading(WebView view, String url){
//读取到url后通过callJava分析调用
JSBridge.callJava(BaseWebLoader.this,view,url);
//如果返回false,则WebView处理链接url,如果返回true,代表WebView根据程序来执行url
return true;
}
里面的关键代码是注册函数,捕获url,执行方法等
API 类实现
实现代码如下
public class BridgeImpl implements IBridge {
/**
* 测试原生方法
*/
public static void testNativeFunc(final BaseWebLoader webLoader, WebView wv, JSONObject param, final Callback callback) {
//可以这样获取参数 param.optString(键值);
//在一个新的线程内执行
new Thread(new Runnable() {
@Override
public void run() {
try {
//执行一些自己的内容
JSONObject object = new JSONObject();
//添加测试信息
object.put("test", "test");
//执行回调
callback.apply(getJSONObject(1, "", object));
} catch (JSONException e) {
e.printStackTrace();
}
}
}).start();
}
}
这个类是一些api的具体实现,webview里面就是注册了这些对应的api
iOS实现部分
说明
这是iOS原生中配套的JSBridge实现代码。iOS中代码是基于UIWebview的,来源于一个github上的开源项目,地址 marcuswestin/WebViewJavascriptBridge
WebViewJavascriptBridgeBase 实现
实现代码如下
@implementation WebViewJavascriptBridgeBase {
__weak id _webViewDelegate;
long _uniqueId;
}
static bool logging = false;
static int logMaxLength = 500;
+ (void)enableLogging { logging = true; }
+ (void)setLogMaxLength:(int)length { logMaxLength = length;}
-(id)init {
self = [super init];
self.messageHandlers = [NSMutableDictionary dictionary];
self.startupMessageQueue = [NSMutableArray array];
self.responseCallbacks = [NSMutableDictionary dictionary];
_uniqueId = 0;
return(self);
}
- (void)dealloc {
self.startupMessageQueue = nil;
self.responseCallbacks = nil;
self.messageHandlers = nil;
}
- (void)reset {
self.startupMessageQueue = [NSMutableArray array];
self.responseCallbacks = [NSMutableDictionary dictionary];
_uniqueId = 0;
}
- (void)sendData:(id)data responseCallback:(WVJBResponseCallback)responseCallback handlerName:(NSString*)handlerName {
NSMutableDictionary* message = [NSMutableDictionary dictionary];
if (data) {
message[@"data"] = data;
}
if (responseCallback) {
NSString* callbackId = [NSString stringWithFormat:@"objc_cb_%ld", ++_uniqueId];
self.responseCallbacks[callbackId] = [responseCallback copy];
message[@"callbackId"] = callbackId;
}
if (handlerName) {
message[@"handlerName"] = handlerName;
}
[self _queueMessage:message];
}
- (void)flushMessageQueue:(NSString *)messageQueueString{
if (messageQueueString == nil || messageQueueString.length == 0) {
NSLog(@"WebViewJavascriptBridge: WARNING: ObjC got nil while fetching the message queue JSON from webview. This can happen if the WebViewJavascriptBridge JS is not currently present in the webview, e.g if the webview just loaded a new page.");
return;
}
id messages = [self _deserializeMessageJSON:messageQueueString];
for (WVJBMessage* message in messages) {
if (![message isKindOfClass:[WVJBMessage class]]) {
NSLog(@"WebViewJavascriptBridge: WARNING: Invalid %@ received: %@", [message class], message);
continue;
}
[self _log:@"RCVD" json:message];
NSString* responseId = message[@"responseId"];
if (responseId) {
WVJBResponseCallback responseCallback = _responseCallbacks[responseId];
responseCallback(message[@"responseData"]);
[self.responseCallbacks removeObjectForKey:responseId];
} else {
WVJBResponseCallback responseCallback = NULL;
NSString* callbackId = message[@"callbackId"];
if (callbackId) {
responseCallback = ^(id responseData) {
if (responseData == nil) {
responseData = [NSNull null];
}
WVJBMessage* msg = @{ @"responseId":callbackId, @"responseData":responseData };
[self _queueMessage:msg];
};
} else {
responseCallback = ^(id ignoreResponseData) {
// Do nothing
};
}
WVJBHandler handler = self.messageHandlers[message[@"handlerName"]];
if (!handler) {
NSLog(@"WVJBNoHandlerException, No handler for message from JS: %@", message);
continue;
}
handler(message[@"data"], responseCallback);
}
}
}
/*这段代码在本文中没有用到
* 因为再原项目中,JSBridge的js库是放在iOS本地沙盒中的,所以才需要手动注入
* 但是本文中的示例,JSBridge是直接在Html中引用的,所以无需注入
- (void)injectJavascriptFile {
NSString *js = WebViewJavascriptBridge_js();
[self _evaluateJavascript:js];
if (self.startupMessageQueue) {
NSArray* queue = self.startupMessageQueue;
self.startupMessageQueue = nil;
for (id queuedMessage in queue) {
[self _dispatchMessage:queuedMessage];
}
}
}
*/
-(BOOL)isCorrectProcotocolScheme:(NSURL*)url {
if([[url scheme] isEqualToString:kCustomProtocolScheme]){
return YES;
} else {
return NO;
}
}
-(BOOL)isQueueMessageURL:(NSURL*)url {
if([[url host] isEqualToString:kQueueHasMessage]){
return YES;
} else {
return NO;
}
}
-(BOOL)isBridgeLoadedURL:(NSURL*)url {
return ([[url scheme] isEqualToString:kCustomProtocolScheme] && [[url host] isEqualToString:kBridgeLoaded]);
}
-(void)logUnkownMessage:(NSURL*)url {
NSLog(@"WebViewJavascriptBridge: WARNING: Received unknown WebViewJavascriptBridge command %@://%@", kCustomProtocolScheme, [url path]);
}
-(NSString *)webViewJavascriptCheckCommand {
return @"typeof WebViewJavascriptBridge == \'object\';";
}
-(NSString *)webViewJavascriptFetchQueyCommand {
return @"JSBridge._fetchQueue();";
}
- (void)disableJavscriptAlertBoxSafetyTimeout {
[self sendData:nil responseCallback:nil handlerName:@"_disableJavascriptAlertBoxSafetyTimeout"];
}
// Private
// -------------------------------------------
- (void) _evaluateJavascript:(NSString *)javascriptCommand {
[self.delegate _evaluateJavascript:javascriptCommand];
}
- (void)_queueMessage:(WVJBMessage*)message {
// if (self.startupMessageQueue) {
// [self.startupMessageQueue addObject:message];
// } else {
// [self _dispatchMessage:message];
// }
[self _dispatchMessage:message];
}
- (void)_dispatchMessage:(WVJBMessage*)message {
NSString *messageJSON = [self _serializeMessage:message pretty:NO];
[self _log:@"SEND" json:messageJSON];
messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"];
messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""];
messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\'" withString:@"\\\'"];
messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"];
messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\r" withString:@"\\r"];
messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\f" withString:@"\\f"];
messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\u2028" withString:@"\\u2028"];
messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\u2029" withString:@"\\u2029"];
NSString* javascriptCommand = [NSString stringWithFormat:@"JSBridge._handleMessageFromNative('%@');", messageJSON];
if ([[NSThread currentThread] isMainThread]) {
[self _evaluateJavascript:javascriptCommand];
} else {
dispatch_sync(dispatch_get_main_queue(), ^{
[self _evaluateJavascript:javascriptCommand];
});
}
}
- (NSString *)_serializeMessage:(id)message pretty:(BOOL)pretty{
return [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:message options:(NSJSONWritingOptions)(pretty ? NSJSONWritingPrettyPrinted : 0) error:nil] encoding:NSUTF8StringEncoding];
}
- (NSArray*)_deserializeMessageJSON:(NSString *)messageJSON {
return [NSJSONSerialization JSONObjectWithData:[messageJSON dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:nil];
}
- (void)_log:(NSString *)action json:(id)json {
if (!logging) { return; }
if (![json isKindOfClass:[NSString class]]) {
json = [self _serializeMessage:json pretty:YES];
}
if ([json length] > logMaxLength) {
NSLog(@"WVJB %@: %@ [...]", action, [json substringToIndex:logMaxLength]);
} else {
NSLog(@"WVJB %@: %@", action, json);
}
}
@end
WebViewJavascriptBridgeBase是JSBridge逻辑代码的基础支持,也就是说这里面封装一些基础的代码,供JSBridge内部调用
WebViewJavascriptBridge 实现
实现代码如下
#if __has_feature(objc_arc_weak)
#define WVJB_WEAK __weak
#else
#define WVJB_WEAK __unsafe_unretained
#endif @implementation WebViewJavascriptBridge {
WVJB_WEAK WVJB_WEBVIEW_TYPE* _webView;
WVJB_WEAK id _webViewDelegate;
long _uniqueId;
WebViewJavascriptBridgeBase *_base;
} /* API
*****/ + (void)enableLogging { [WebViewJavascriptBridgeBase enableLogging]; }
+ (void)setLogMaxLength:(int)length { [WebViewJavascriptBridgeBase setLogMaxLength:length]; } + (instancetype)bridgeForWebView:(WVJB_WEBVIEW_TYPE*)webView {
WebViewJavascriptBridge* bridge = [[self alloc] init];
[bridge _platformSpecificSetup:webView];
return bridge;
} - (void)setWebViewDelegate:(WVJB_WEBVIEW_DELEGATE_TYPE*)webViewDelegate {
_webViewDelegate = webViewDelegate;
} - (void)send:(id)data {
[self send:data responseCallback:nil];
} - (void)send:(id)data responseCallback:(WVJBResponseCallback)responseCallback {
[_base sendData:data responseCallback:responseCallback handlerName:nil];
} - (void)callHandler:(NSString *)handlerName {
[self callHandler:handlerName data:nil responseCallback:nil];
} - (void)callHandler:(NSString *)handlerName data:(id)data {
[self callHandler:handlerName data:data responseCallback:nil];
} - (void)callHandler:(NSString *)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback {
[_base sendData:data responseCallback:responseCallback handlerName:handlerName];
} - (void)registerHandler:(NSString *)handlerName handler:(WVJBHandler)handler {
_base.messageHandlers[handlerName] = [handler copy];
} - (void)disableJavscriptAlertBoxSafetyTimeout {
[_base disableJavscriptAlertBoxSafetyTimeout];
} /* Platform agnostic internals
*****************************/ - (void)dealloc {
[self _platformSpecificDealloc];
_base = nil;
_webView = nil;
_webViewDelegate = nil;
} - (NSString*) _evaluateJavascript:(NSString*)javascriptCommand
{
return [_webView stringByEvaluatingJavaScriptFromString:javascriptCommand];
} /* Platform specific internals: OSX
**********************************/
#if defined WVJB_PLATFORM_OSX - (void) _platformSpecificSetup:(WVJB_WEBVIEW_TYPE*)webView {
_webView = webView; _webView.policyDelegate = self; _base = [[WebViewJavascriptBridgeBase alloc] init];
_base.delegate = self;
} - (void) _platformSpecificDealloc {
_webView.policyDelegate = nil;
} - (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id)listener
{
if (webView != _webView) { return; }
NSURL *url = [request URL]; if ([_base isCorrectProcotocolScheme:url]) {
if ([_base isBridgeLoadedURL:url]) {
[_base injectJavascriptFile];
} else if ([_base isQueueMessageURL:url]) {
NSString *messageQueueString = [self _evaluateJavascript:[_base webViewJavascriptFetchQueyCommand]];
[_base flushMessageQueue:messageQueueString];
} else {
[_base logUnkownMessage:url];
}
[listener ignore];
} else if (_webViewDelegate && [_webViewDelegate respondsToSelector:@selector(webView:decidePolicyForNavigationAction:request:frame:decisionListener:)]) {
[_webViewDelegate webView:webView decidePolicyForNavigationAction:actionInformation request:request frame:frame decisionListener:listener];
} else {
[listener use];
}
} /* Platform specific internals: iOS
**********************************/
#elif defined WVJB_PLATFORM_IOS - (void) _platformSpecificSetup:(WVJB_WEBVIEW_TYPE*)webView {
_webView = webView;
_webView.delegate = self;
_base = [[WebViewJavascriptBridgeBase alloc] init];
_base.delegate = self;
} - (void) _platformSpecificDealloc {
_webView.delegate = nil;
} - (void)webViewDidFinishLoad:(UIWebView *)webView {
if (webView != _webView) { return; } __strong WVJB_WEBVIEW_DELEGATE_TYPE* strongDelegate = _webViewDelegate;
if (strongDelegate && [strongDelegate respondsToSelector:@selector(webViewDidFinishLoad:)]) {
[strongDelegate webViewDidFinishLoad:webView];
}
} - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
if (webView != _webView) { return; } __strong WVJB_WEBVIEW_DELEGATE_TYPE* strongDelegate = _webViewDelegate;
if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didFailLoadWithError:)]) {
[strongDelegate webView:webView didFailLoadWithError:error];
}
}
//捕获url,并进行分析
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
if (webView != _webView) { return YES; }
NSURL *url = [request URL];
__strong WVJB_WEBVIEW_DELEGATE_TYPE* strongDelegate = _webViewDelegate;
if ([_base isCorrectProcotocolScheme:url]) {
if ([_base isBridgeLoadedURL:url]) {
[_base injectJavascriptFile];
} else if ([_base isQueueMessageURL:url]) {
NSString *messageQueueString = [self _evaluateJavascript:[_base webViewJavascriptFetchQueyCommand]];
[_base flushMessageQueue:messageQueueString];
} else {
[_base logUnkownMessage:url];
}
return NO;
} else if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:shouldStartLoadWithRequest:navigationType:)]) {
return [strongDelegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType];
} else {
return YES;
}
} - (void)webViewDidStartLoad:(UIWebView *)webView {
if (webView != _webView) { return; } __strong WVJB_WEBVIEW_DELEGATE_TYPE* strongDelegate = _webViewDelegate;
if (strongDelegate && [strongDelegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
[strongDelegate webViewDidStartLoad:webView];
}
} #endif @end
WebViewJavascriptBridge是主要的JSBridge逻辑实现代码
Webview容器关键代码 实现
实现代码如下
建立JSBridge桥梁
- (void)viewDidLoad {
[super viewDidLoad];
// 一些其它操作
// WebViewJavascriptBridge
// 给webView建立JS和OC的沟通桥梁
[WebViewJavascriptBridge enableLogging];
self.bridge = [WebViewJavascriptBridge bridgeForWebView:self.wv];
[self.bridge setWebViewDelegate:self];
[self registAPIForJS];
}
注册API方法
- (void)registAPIForJS
{
// 测试原生方法
[self.bridge registerHandler:@"testNativeFunc" handler:^(id data, WVJBResponseCallback responseCallback) {
//可以这样获取参数
NSString *str = data[@"key值"]; //可以做一些自己的事情
}];
}
捕获url scheme并执行方法的代码
//关键是这句代码
[self.bridge setWebViewDelegate:self];
//然后再WebViewJavascriptBridge里就可以重新shouldStartLoadWithRequest来捕获url了 文章来源:http://www.cnblogs.com/dailc/p/5931328.html
JSBridge实现示例的更多相关文章
- Hybrid APP基础篇(五)->JSBridge实现示例
说明 JSBridge实现示例 目录 前言 参考来源 楔子 JS实现部分 说明 实现 Android实现部分 说明 JSBridge类 实现 Callback类 实现 Webview容器关键代码 实现 ...
- Hybrid APP基础篇(四)->JSBridge的原理
说明 JSBridge实现原理 目录 前言 参考来源 前置技术要求 楔子 原理概述 简介 url scheme介绍 实现流程 实现思路 第一步:设计出一个Native与JS交互的全局桥对象 第二步:J ...
- 【quickhybrid】JSBridge的实现
前言 本文介绍quick hybrid框架的核心JSBridge的实现 由于在最新版本中,已经没有考虑iOS7等低版本,因此在选用方案时没有采用url scheme方式,而是直接基于WKWebView ...
- JSBridge的实现
JSBridge是Native代码与JS代码的通信桥梁.目前的一种统一方案是:H5触发url scheme->Native捕获url scheme->原生分析,执行->原生调用h5. ...
- H5与Native交互之JSBridge技术
一.原理篇 下面分别介绍IOS和Android与Javascript的底层交互原理 IOS 在讲解原理之前,首先来了解下iOS的UIWebView组件,先来看一下苹果官方的介绍: You can us ...
- JSBridge的原理
前言 参考来源 前人栽树,后台乘凉,本文参考了以下来源 github-WebViewJavascriptBridge JSBridge-Web与Native交互之iOS篇 Ios Android Hy ...
- Hybrid app本地开发如何调用JSBridge
前天同事问我公司内部的小程序怎么对接的,我回忆了一下,简单记录了一下前端同学需要注意的点. 背后还有小程序架构.网络策略等等.当时恰逢小程序架构调整,(老架构的时候我就发现了有一个问题点可以优化,但是 ...
- Swift3.0服务端开发(一) 完整示例概述及Perfect环境搭建与配置(服务端+iOS端)
本篇博客算是一个开头,接下来会持续更新使用Swift3.0开发服务端相关的博客.当然,我们使用目前使用Swift开发服务端较为成熟的框架Perfect来实现.Perfect框架是加拿大一个创业团队开发 ...
- .NET跨平台之旅:将示例站点升级至 ASP.NET Core 1.1
微软今天在 Connect(); // 2016 上发布了 .NET Core 1.1 ,ASP.NET Core 1.1 以及 Entity Framework Core 1.1.紧跟这次发布,我们 ...
随机推荐
- PH复合电极的结构、测量原理及注意事项
PH复合电极的结构.测量原理及注意事项 PH计是很多实验中常用的仪器.如细胞培养基的配制.各种洗脱缓冲液的配制等.然而人们很容易忽视它,只知其然不知其所以然.当遇到测量不准确时,往往无从分析.下面从三 ...
- STL容器与拷贝构造函数
所有容器提供的都是“value语意”而非“reference语意”.容器内进行元素的安插操作时,内部实施的是拷贝操作,置于容器内.因此STL容器 的每一个元素都必须能够拷贝.---<<C+ ...
- 2.高并发教程-基础篇-之nginx+mysql实现负载均衡和读写分离
技巧提示:mysql读写分离搭建好之后,配合nginx的负载均衡,可以高效的mysql的集群性能,同时免去麻烦的query分流.比如,sever1收到的请求就专门链接slave1从mysql读取数据, ...
- Spring第四天——SSH整合
(从整合开始,使用回归使用eclipse) 一.三大框架版本: struts2 hibernate5 spring4 二.SSH三大框架回顾: Hibernate: ORM思想 核心配置文件: 单独 ...
- Kali-linux本地权限提升
上一节介绍了窃取目标系统令牌,现在来介绍窃取令牌后如何提升在目标系统上的权限.提升本地权限可以使用户访问目标系统,并且进行其他的操作,如创建用户和组等.本节将介绍本地权限提升. 同样的实现本地权限提升 ...
- 20145234黄斐《java程序设计》第十三周代码检查
在IDEA中对P145 MathTool.java 使用JUnit进行单元测试,测试用例不少于三个,要包含正常情况,边界情况. 提交测试代码和运行结果截图,加上学号水印,提交码云代码链接. 码云链接 ...
- c++ 绘制方框
知识点: GetStdHandle函数 FillConsoleOutputCharacter函数 SetConsoleCursorPosition函数 system函数 一. GetStdHandle ...
- 在CMD 中,如何切换python2.x 版本 和 python3.x版本?
1.cmd中输入python,启动python2.x版本,如何切换呢? 2.找到python2.x安装路径,修改python.exe名称为:python27.exe 3. 打开cmd,输入python ...
- 3-1 实现简单的shell sed替换功能
1.需求 程序1: 实现简单的shell sed替换功能 file1 的内容copy到file2 输入参数./sed.py $1 $2 $1替换成$2 (把a替换成% ) 2.个人思路 open ...
- OpenStack入门篇(二十)之实现阿里云ESC多FLAT网络
1.给两台虚拟机增加网卡,使用仅主机模式,网段为:192.168.57.0/24 2.修改两台主机网卡配置 [root@linux-node1 ~]# cp /etc/sysconfig/networ ...