Skip to content

mendixlabs/mendix-native-webview-revamped

Repository files navigation

Apache License Support Studio

Mendix Native Web View (Revamped)

NOTE: This widget is not production ready (hence we're going with a lower version number) and should only be used when applicable. I haven't published this widget to the MarketPlace yet.

This is a work-in-progress rewrite of the Web View widget that is part of the Native Mobile Resources, published by Mendix R&D.

This may or may not be incorporated in the original widget eventually.

Differences

  • Based on reavt-native-webview version 11.17.1
  • Rewrote in a Functional component, not class.
  • Removed OnLoad (useless, can be replaced by Navigation)
  • Added an option to expose the webview to the page (Experimental, see below)
  • Added more attributes for different Events (all JSON stringified):
    • Error -> General errors in the webview.
    • HTTP_Error -> Specific HTTP Errors.
    • Navigation -> Triggered when a page is loading (loading: true) or loaded (loading: false)
    • Message -> This is used in conjunction with window.ReactNativeWebView.postMessage([string]) in the loaded page itself.

Events

For every type of event mentioned above, the widget will stringify a JSON of the event and add this to the attribute. It will then trigger the action. The best way to handle this is by executing a Nanoflow.

  1. Domain Model

domain-model

This is the domain model I use. The widget uses the Url attribute to view a certain page, the Navigation attribute is used in the widget to track navigation changes

  1. Nanoflow

nanoflow

On Navigation (see Events tab in the widget) is triggered, which contains a Javascript Action. This action will take the JSON string out of the Navigation attribute and convert this to a new WebViewEvent object. You can do anything with it afterwards.

  1. Javascript Action

jsaction

The code (click to open) might be changed. I noted that the attribute names might not always correspond with the keys in the JSON

JS Action code
// This file was generated by Mendix Studio Pro.
//
// WARNING: Only the following code will be retained when actions are regenerated:
// - the import list
// - the code between BEGIN USER CODE and END USER CODE
// - the code between BEGIN EXTRA CODE and END EXTRA CODE
// Other code you write will be lost the next time you deploy the project.
import { Big } from "big.js";

// BEGIN EXTRA CODE
function createMxObject(entity) {
    return new Promise((resolve, reject) => {
        mx.data.create({
            entity,
            callback: resolve,
            error: () => reject(new Error(`Could not create '${entity}' object`))
        });
    });
}
async function createParamObject(entity, data) {
    const mxObject = await createMxObject(entity);
    mxObject.getAttributes().forEach(attributeName => {
        const value = data[attributeName.toLocaleLowerCase()];
        if (value) {
            mxObject.set(attributeName, value);
        }
    });
    return mxObject;
}
// END EXTRA CODE

/**
 * @param {string} jSON
 * @param {string} entity
 * @returns {Promise.<MxObject>}
 */
export async function Importer(jSON, entity) {
	// BEGIN USER CODE
	if (!jSON) {
		return createMxObject(entity);
	}
	try {
		const obj = JSON.parse(jSON);
		if (obj) {
			return createParamObject(entity, obj);
		}

	} catch (e) {
		console.warn(e);
	}

	return createMxObject(entity);
	// END USER CODE
}

Basically, the JS Action will create a new object, go over all the attributes and fill these with the values found in the JSON.

You might ask... "Why?". Well, I want the widget to not alter any info (in onNavigation, onMessage, onError etc) and give the Mendix Developer the possibility to do whatever they want with it. That's why I create separate entities that can be filled, so you can then properly process it in your Nanoflows

Yes, the JS Action is not the cleanest solution, but unfortunately we can't use proper JSON structures and import mappings in Native.

Expose

NOTE: This is HIGHLY experimental and I don't know if this works in production. In my tests it worked in the Make it Native app, but haven't tested it in production. Don't use it if you don't need to!

There is an option in Advanced that can be used to expose your widget to the window object.

  • Let's say your widget name is webview_Revamped (see widget tab Common)
  • Switch on Expose to window in Advanced
  • Now you could potentially access the webview from a Javascript Action using window[widgetName] (where widgetName is "webview_Revamped" in this case)

Why?

/**
 * @param {string} webViewName
 * @returns {Promise.<void>}
 */
export async function JS_WebView_Go_Forward(webViewName) {
	// BEGIN USER CODE
	const view = window[webViewName];
	if (view && view.goForward) {
		view.goForward();
	}
	// END USER CODE
}

You can fire a few events on the webview component. There are interesting things you could do.

See react-native-webview methods

This can potentially be used to for example stop the webview from loading, inject custom javascript in the page itself etc.

Styling

See official Mendix Docs, the class name should be:

TBD, figuring this one out

Development and contribution

  1. Install NPM package dependencies by using: npm install. If you use NPM v7.x.x, which can be checked by executing npm -v, execute: npm install --legacy-peer-deps.
  2. Run npm start to watch for code changes. On every change:
    • the widget will be bundled;
    • the bundle will be included in a dist folder in the root directory of the project;
    • the bundle will be included in the deployment and widgets folder of the Mendix test project.

License

Apache-2