JockeyJS 是一个双平台的 iOS 和 Android 库,它简化了本地应用和运行其中的 JavaScript 应用之间的双向通信。
JockeyJS 将帮助您的 iOS 应用与运行在 UIWebview 内的 JavaScript 应用进行通信。
JockeyJS/includes/Jockey.m
和 Jockey.h
添加到您的项目中。JockeyJS/js/jockey.js
作为 script 标签。JockeyViewController
)的代理,然后添加以下方法到 ViewController 的 .m
文件-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
return [Jockey webView:webView withUrl:[request URL]];
}
JockeyJS 将帮助您的 Android 应用与运行在 WebView 内的 JavaScript 应用进行通信。
JockeyJS/js/jockey.js
作为 script 标签。您可以在 Android 应用中使用 Jockey 的两种方式。
第一种情况是如果您计划在单个活动中使用 Jockey 或要在活动之间保持实例分离
//Declare an instance of Jockey
Jockey jockey;
//The WebView that we will be using, assumed to be instantiated either through findViewById or some method of injection.
WebView webView;
WebViewClient myWebViewClient;
@Override
protected void onStart() {
super.onStart();
//Get the default JockeyImpl
jockey = JockeyImpl.getDefault();
//Configure your webView to be used with Jockey
jockey.configure(webView);
//Pass Jockey your custom WebViewClient
//Notice we can do this even after our webView has been configured.
jockey.setWebViewClient(myWebViewClient)
//Set some event handlers
setJockeyEvents();
//Load your webPage
webView.loadUrl("file:///your.url.com");
}
第二种选择是利用 JockeyService,这在您想在多个活动或应用之间共享事件处理程序或在确保 Jockey 的生命周期明确绑定到您应用的生命周期时非常有用。
以下是如何本地绑定到 JockeyService 的示例,请参阅Android 文档以了解更多有关此过程的详细信息。
如果您打算将 Jockey 作为服务使用,请确保将其包含在您的应用清单中,否则您将无法绑定它。
//First we declare the members involved in using Jockey
//A WebView to interact with
private WebView webView;
//Our instance of the Jockey interface
private Jockey jockey;
//A helper for binding services
private boolean _bound;
//A service connection for making use of the JockeyService
private ServiceConnection _connection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
_bound = false;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
JockeyBinder binder = (JockeyBinder) service;
//Retrieves the instance of the JockeyService from the binder
jockey = binder.getService();
//This will setup the WebView to enable JavaScript execution and provide a custom JockeyWebViewClient
jockey.configure(webView);
//Make Jockey start listening for events
setJockeyEvents();
_bound = true;
//Redirect the WebView to your webpage.
webView.loadUrl("file:///android_assets/index.html");
}
}
///....Other member variables....////
//Then we bind the JockeyService to our activity through a helper function in our onStart method
@Override
protected void onStart() {
super.onStart();
JockeyService.bind(this, _connection);
}
//In order to bind this with the Android lifecycle we need to make sure that the service also shuts down at the appropriate time.
@Override
protected void onStop() {
super.onStop();
if (_bound) {
JockeyService.unbind(this, _connection);
}
}
您已经准备就绪!现在您可以从应用到 JavaScript 传递事件。
JockeyJS 允许您不仅向 JavaScript 应用发送事件,而且当所有 JavaScript 监听器执行完毕后,还可以通过块的形式接收回调。有两种方法可用
// Send an event to JavaScript, passing a payload.
// payload can be an NSDictionary or NSArray, or anything that is serializable to JSON.
// It can be nil.
[Jockey send:@"event-name" withPayload:payload toWebView:webView];
// If you want to send an event and also execute code within the iOS app when all
// JavaScript listeners have finished processing.
[Jockey send:@"event-name" withPayload:payload toWebView:webView perform:^{
// Respond to callback.
}];
// Send an event to JavaScript, passing a payload
jockey.send("event-name", webView, payload);
//With a callback to execute after all listeners have finished
jockey.send("event-name", webView, payload, new JockeyCallback() {
@Override
public void call() {
//Your execution code
}
});
在Jockey中,事件监听器基于jQuery的事件监听器(功能远不止如此)。要在JavaScript应用程序中接收上述事件,仅需添加以下代码到您的JavaScript应用程序中
// Listen for an event from iOS and log the payload.
Jockey.on("event-name", function(payload) {
console.log(payload);
});
在您的监听器引发其他事件且您不希望在iOS收到回调之前完成这些事件的情况下,您可以将一个稍微不同的函数传递给on()
。例如:
// Listen for an event from iOS, but don't notify iOS we've completed processing
// until an asynchronous function has finished (in this case a timeout).
Jockey.on("event-name", function(payload, complete) {
// Example of event'ed handler.
setTimeout(function() {
alert("Timeout over!");
complete();
}, 1000);
});
// Stop listening to an event from ios
Jockey.off("event-name");
与iOS类似,Jockey的JavaScript库允许您将事件从JavaScript应用程序传递到iOS应用程序。
// Send an event to iOS.
Jockey.send("event-name");
// Send an event to iOS, passing an optional payload.
Jockey.send("event-name", {
key: "value"
});
// Send an event to iOS, pass an optional payload, and catch the callback when all the
// iOS listeners have finished processing.
Jockey.send("event-name", {
key: "value"
}, function() {
alert("iOS has finished processing!");
});
与JavaScript类似,Jockey的iOS库有方法可以帮助您轻松监听来自JavaScript应用程序的事件
// Listen for an event from JavaScript and log the payload.
[Jockey on:@"event-name" perform:^(NSDictionary *payload) {
NSLog(@"payload = %@", payload);
}];
// Listen for an event from JavaScript, but don't notify the JavaScript that
// the listener has completed until an asynchronous function has finished.
[Jockey on:@"event-name" performAsync:^(NSDictionary *payload, void (^complete)()) {
// Do something asynchronously, then call the complete() method when finished.
}];
// Stop listening for events from javascript, Jockey is a shared instance after first initialization
// If you're webview controller is initialized and deinitialized, this is useful.
[Jockey off:@"event-name"];
//Listen for an event from JavaScript and log a message when we have receied it.
jockey.on("event-name", new JockeyHandler() {
@Override
protected void doPerform(Map<Object, Object> payload) {
Log.d("jockey", "Things are happening");
}
});
//Listen for an event from JavaScript, but don't notify the JavaScript that the listener has completed
//until an asynchronous function has finished
//Note: Because this method is executed in the background, if you want the method to interact with the UI thread
//it will need to use something like a android.os.Handler to post to the UI thread.
jockey.on("event-name", new JockeyAsyncHandler() {
@Override
protected void doPerform(Map<Object, Object> payload) {
//Do something asynchronously
//No need to called completed(), Jockey will take care of that for you!
}
});
//We can even chain together several handlers so that they get processed in sequence.
//Here we also see an example of the NativeOS interface which allows us to chain some common
//system handlers to simulate native UI interactions.
jockey.on("event-name", nativeOS(this)
.toast("Event occurred!")
.vibrate(100), //Don't forget to grant permission
new JockeyHandler() {
@Override
protected void doPerform(Map<Object, Object> payload) {
}
}
);
//...More Handlers
//If you would like to stop listening for a specific event
jockey.off("event-name");
//If you would like to stop listening to ALL events
jockey.clear();
您需要确保您的iOS应用程序仅对您控制的域发送的事件做出响应(例如,如果您的UIWebView允许用户导航到其他页面,您不希望其他页面能够与或控制您的iOS应用程序)。要这样做,请在设置时添加到您ViewController中添加的方法内部的检查
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
// Get current URL of the webview through Javascript.
NSString *urlString = [_webView stringByEvaluatingJavaScriptFromString:@"window.location.href"];
NSURL *currentURL = [NSURL URLWithString:urlString];
NSString *host = [currentURL host];
if ([host isEqualToString:@"mydomain.com") {
return [Jockey webView:webView withUrl:[request URL]];
}
return TRUE;
}
jockey.setValidationListener(new OnValidateListener() {
@Override
public boolean validate(String host) {
return "mydomain.com".equals(host);
}
});