THIS PROJECT IS UNMAINTAINED AND SHOULD NOT BE USED. Blazor Hybrid is a similar concept and currently under active development.
Simple C# – JavaScript bridge for building hybrid iOS and Android apps.
- Call script functions and get/set values on script objects from C# using
dynamic
- Marshals simple values between script and C# by value (JSON)
- Marshals complex script objects to C# by reference
- Catch script exceptions in C#
- Call C# methods from a script within a web view.
- Attach C# event handlers to events on script objects.
- Create strongly-typed wrappers for JavaScript APIs.
To start utilizing HybridKit, follow the steps below:
- Add HybridKit to your app. NuGet is the recommended way to do this.
- Add the following references to your project:
Microsoft.CSharp
Xamarin.Forms
(currently required, even if your project does not use it.)- For Android only:
Mono.Android.Export
HybridKit currently requires Xamarin.Forms 1.3.1 or later. If you install HybridKit through NuGet, it will install an appropriate version for you automatically.
On iOS, the HybridKit API is exposed as extension methods on UIWebView
. Declare a new UIWebView
, as shown in the code snippet below:
using UIKit;
using HybridKit;
// ...
var webView = new UIWebView ();
On Android, create an instance of HybridKit.Android.HybridWebView
. This class extends Android.WebKit.WebView
and will need to be configured in the same way—generally at least enabling JavaScript, as shown below:
using HybridKit.Android;
// ...
var webView = new HybridWebView ();
webView.Settings.JavaScriptEnabled = true;
When using Xamarin.Forms on iOS or Android, create a new HybridKit.Forms.HybridWebView
, which extends from Xamarin.Forms.WebView
:
using HybridKit.Forms;
// ... On the native app:
HybridWebViewRenderer.Init ();
// ... In the shared code:
var webView = new HybridWebView ();
You may want to load an HTML file that is bundled with your app into the web view. HybridKit makes this easier by suppling the LoadFromBundle
extension method on iOS and Android:
webView.LoadFromBundle ("index.html");
For Xamarin.Forms, HybridKit supplies the BundleWebViewSource
class:
webView.Source = new BundleWebViewSource ("index.html");
The path passed into both of these APIs is the bundle-relative path on iOS, or the path relative to the Assets folder for an Android project.
To execute script inside the web view, call RunScriptAsync
on the web view.
Although the name of this method ends with "Async," it may actually run synchronously depending on the threading constraints of the current platform (see important note about threading below). Generally, you'll want to await the Task
returned by this method, which simulates a synchronous method call in either case:
await webView.RunScriptAsync (window => {
var name = window.prompt ("What is your name?") ?? "World";
var node = window.document.createTextNode (string.Format ("Hello {0} from C#!", name));
window.document.body.appendChild (node);
});
The window
argument to the lambda is the JavaScript global object. In the example above, the JavaScript prompt
function is called, which displays a dialog to the user, and returns their entered text (or the string "World" if they click Cancel). It then creates a new text node and appends it to the DOM. You can see this code in action in the KitchenSink sample app.
Important Note about Threading
Within the script lambda passed to RunScriptAsync
, HybridKit evaluates JavaScript synchronously. Unfortunately, different platforms have different requirements for this:
- On iOS, all calls into JavaScript must be done from the main UI thread.
- On newer versions of Android (KitKat and later), it will deadlock if a call to JavaScript is made synchronously from the main UI thread.
To accommodate these different requirements, the RunScriptAsync
method may dispatch to a different thread to run the passed lambda. Because of this, you must be careful to properly synchronize external objects used in the lambda, and take proper care of any script objects persisted outside the scope of the lambda. Script objects may be used safely in multiple RunScriptAsync
calls. Best practice for this is shown below:
DO NOT do this! – It causes an implicit ToString
call on the current thread, which might not work:
dynamic foo;
await webView.RunScriptAsync (window => {
foo = window.foo;
});
// ...
Console.WriteLine (foo);
This is OK – the RunScriptAsync
method ensures the implicit ToString
call happens on the correct thread:
dynamic foo;
await webView.RunScriptAsync (window => {
foo = window.foo;
});
// ...
await webView.RunScriptAsync (_ => Console.WriteLine (foo));
This project is brand new, so expect bugs. Feedback and contributions are always welcome!
After cloning this repository, you'll also need to update the submodules:
git submodule update --init --recursive
I've been working in Xamarin Studio on the Mac, in which you can simply open HybridKit.sln
and hit build.
On Windows, I've heard reports of compilation issues, probably due to some C# 6 features used in the codebase. If you're on Windows, try compiling with Roslyn or the mcs
compiler from Mono. If you get it working, let me know and I'll update this section.
Run the HybridKit.Tests.Android
or HybridKit.Tests.iOS
projects to run the tests on Android or iOS, respectively.