JockeyJS 1.0.0

JockeyJS 1.0.0

测试已测试
语言语言 Objective-CObjective C
许可协议 MIT
发布日期上次发布2014年12月

Min Kim维护。



JockeyJS 1.0.0

  • Tim Coulter

JockeyJS 是一个双平台的 iOS 和 Android 库,它简化了本地应用和运行其中的 JavaScript 应用之间的双向通信。

设置 - iOS

JockeyJS 将帮助您的 iOS 应用与运行在 UIWebview 内的 JavaScript 应用进行通信。

  1. 在您的 iOS 项目目录中下载最新的 JockeyJS。
  2. 通过右击 XCode 的项目导航器并选择“将文件添加到 <您的项目>”,将 JockeyJS/includes/Jockey.mJockey.h 添加到您的项目中。
  3. 确保在您的网络应用中包含 JockeyJS/js/jockey.js 作为 script 标签。
  4. 最后,将您的 ViewController 设置为 UIWebView (示例中的 JockeyViewController)的代理,然后添加以下方法到 ViewController 的 .m 文件
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    return [Jockey webView:webView withUrl:[request URL]];
}

设置 - Android

JockeyJS 将帮助您的 Android 应用与运行在 WebView 内的 JavaScript 应用进行通信。

  1. 下载最新的 JockeyJS.Android 项目。
  2. 在您的 Android 应用中添加 JockeyJS.Android 的库引用(在 Eclipse 中,这通过右键单击项目 -> 属性 -> Android -> 添加.. 实现)
  3. 确保在您的网络应用中包含 JockeyJS/js/jockey.js 作为 script 标签。
  4. 将 Jockey 添加到您的应用。

您可以在 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 传递事件。

从应用到 JavaScript 发送事件

JockeyJS 允许您不仅向 JavaScript 应用发送事件,而且当所有 JavaScript 监听器执行完毕后,还可以通过块的形式接收回调。有两种方法可用

iOS
// 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.
}];
Android
// 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
    }
});

JavaScript中处理应用事件

在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");

从JavaScript向应用发送事件

与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的事件

iOS

与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"];
Android
//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

您需要确保您的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;
}
Android
jockey.setValidationListener(new OnValidateListener() {
    @Override
    public boolean validate(String host) {
        return "mydomain.com".equals(host);
    }
});

贡献者

  • @tcoulter - 原始作者(仅限iOS)
  • @paulpdaniels - Android支持