An Advanced Web View based Maui Project. This project was inspired from Cordova/Capacitor. However, building native plugins is very time consuming. Maui offers single language to write native plugins easy on any platform. So we decided to create Capacitor/Electron-JS for Maui.
Why?
Well C# is better language when we want to develop native apps for Android and iOS, however writing everything in C# and deploying app is very time consuming as every build needs to go through app store approvals. Often app store reviewers have no idea about the apps and they keep on clicking on the most unused parts of apps and complain about something trivial and reject the approval.
We wanted to use Capacitor or React Native, but both of them suffer plugin creation as plugins has to be created in native languages, (Java for Android and Swift on iOS), which requires two separate set of codebases and different expertise.
So we decided to build a PositronWebView
that offers easy hybrid app creation along with simple API to access Device's native interface.
Is HTML Fast?
With recent advancement in HTML5 + CSS3 and JavaScript updates, creating web UI is easier than native UI, you can create almost all effects in HTML. The key to make app superfast is to drop the bulky JavaScript Frameworks, for example using instead of using $('.price').text("$20")
you should use document.getElementsById("price").textContent = "$20"
.
Try to use inbuilt CSS animation vs JavaScript to emulate animations.
Our own Web Atoms framework is superfast, but you have your own choice to use any framework you want with PositronWebView
.
Getting Started
- Create an empty folder
- Run
npm init
- Run
npm install -s @positron-js/cli
- Run
node ./node_modules/@positron-js/cli init
- Run
npm install
This will create a maui project inside maui folder. Along with build scripts to publish.
Open Web URL
PositronWebView
expects URL for website, you can directly open remote URL and expose positron
context. You can also limit exposure of positron
context by setting ShouldInvokeScript
delegate.
The url is set in build script's config.js
file, you can also configure url in appsetting.json
file.
Access .NET API
Positron exposes positron property on window object, with run method. Positron installs JavaScript engine (YantraJS in Android and JavaScriptCore in iOS), which integrates with CLR. So you can write JavaScript that access CLR objects directly.
Example - Get DeviceToken
Lets assume that we have configured push messaging and we want to retrieve the device token. (For convenience, we have created Positron class that gives you deviceToken), you have to enable RegisterPushMessaging
in MauApplication.cs
file, which is commented by default as it gives build errors if google-services.json
is not configured correctly.
import PositronInBrowser from "@positron-js/context/index.js";
/** Although syntactically correct, this function
* will be executed inside Positron's JavaScript Engine.
* And the result will be available after successful execution.
*
* This function cannot contain any closer except `global`;
*/
/** Basically positron.run() will send script text and parameters */
/* (as json) to Positron's JavaScript engine */
const deviceToken = await PositronInBrowser.run(function () {
// this runs inside App's Internal JavaScript Engine
const NSPositronAssembly = this.clr
.assembly("NeuroSpeech.Positron");
const Positron = NSPositronAssembly
// following is fully qualified name
.NeuroSpeech.Positron.Positron;
return Positron.deviceToken;
});
Example - Open Url
Lets assume you want to open native browser instead of navigating WebView.
import PositronInBrowser from "@positron-js/context/index.js";
await PositronInBrowser.run({url}, function (p) {
const Essentials = this.clr.assembly("Microsoft.Maui.Essentials");
const Browser = Essentials.Microsoft.ApplicationModel.Browser;
Browser.default.openAsync(p.url);
}, "https://socialmail.me")
Note, we are sending parameters as first parameter in call to run
method. And same parameters object can be accessed inside function(p)
. You can only pass plain non recursive primitive types in parameters. As they are sent to Positron as JSON.
Example - Create New Instance
import PositronInBrowser from "@positron-js/context/index.js";
await PositronInBrowser.run({url}, function (p) {
const Essentials = this.clr.assembly("Microsoft.Maui.Essentials");
const Graphics = this.clr.assembly("Microsoft.Maui.Graphics");
const { Browser, BrowserLaunchOptions } = Essentials
.Microsoft.ApplicationModel;
const { Colors } = Graphics.Microsoft.Maui.Graphics;
const options = new BrowserLaunchOptions();
options.preferredToolbarColor = Colors.orange;
await Browser.openAsync(p.url, options);
}, "https://socialmail.me")
Positron Context
PositronWebView
creates a new JavaScript context (JavaScriptCore in iOS and YantraJS on other platforms) and it exposes clr.assembly
function, which you can access by calling this.clr.assembly
, from this assembly you can easily access namespaces and types.
Once you have types, you can call methods or construct an objects from it.
For convenience we have created @positron-js/context
npm package which exposes typescript definitions for Microsoft.Maui.Graphics
, Microsoft.Maui.Essentials
and NeuroSpeech.Positron
assemblies.
You can add your own assemblies easier, the source code is available on github https://github.com/Positron-JS/context
AOT and Linking
For PositronWebView
to access all CLR objects, Linking must be disabled and interpreter must be turned on, these settings are automatically set when cli creates a sample project.
Using interpreter, reduces code size, but it does add performance overhead. However, if you do your most stuff inside HTML, browser's native performance will take care of everything. And if you only need to occasionally access .NET APIs such as geolocation or push registration token, select files etc, there would be no visible performance issues.
Publishing
To publish the project, you must execute .jsx
file with @neurospeech/jex
as shown below.
node ./node_modules/@neurospeech/jex/index.js ./build-android.jsx
Jex is a new scripting engine that executes jsx files as a build script, and you can easily edit them and utilize JavaScript in the build script.
You just have to configure environment variables and put your certificates in cert folder, you can review build-%%%%%-config.js
file to find out what every platform needs.
Positron Web View Repository
Positron-JS / positron-web-view
Positron JS WebView for MAUI
Positron Web View
An Advanced Web View based Maui Project. This project was inspired from Cordova/Capacitor. However, building native plugins is very time consuming. Maui offers single language to write native plugins easy on any platform. So we decided to create Capacitor for Maui.
Get Started
- Create an empty folder
- Run
npm init
- Run
npm install -s @positron-js/cli
- Run
node ./node_modules/@positron-js/cli init
- Run
npm install
again.
This will create a maui project inside maui folder. Along with build scripts to publish.
Publish
To publish the project, you must execute .jsx
file with @neurospeech/jex
as shown below.
node ./node_modules/@neurospeech/jex/index.js ./build-android.jsx
Jex is a new scripting engine that executes jsx files as a build script, and you can easily edit them and utilize JavaScript in the build script.
Access .NET Inside Browser
Positron exposes positron
property on window
object, with run
method. Positron installs JavaScript engine (YantraJS in Android and JavaScriptCore in…
Top comments (0)