-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
feat: add script message handler support to Android WebView #14328
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat: add script message handler support to Android WebView #14328
Conversation
|
The example code will show |
|
@m1ga It might have something to do with the synchronisation of the web-page script loading and adding the app side message handler. Can you try to call the web-page side method I tested both Android and iOS changes upon a button click rather than instantly running the script, but I added the sample code here for simplicity. |
|
I've used the Chrome Devtools to inspect the webview and even using the console I don't have |
|
@m1ga I checked the native docs, and found that the script must be injected either before the URL is loaded or the URL must be reload after. In my tests, the web-page does some redirections. Can you please set the webView URL after the |
|
Still no luck: const HANDLER_NAME = 'MyScriptMessageHandler';
const window = Ti.UI.createWindow({ title: 'Android Script Message' });
const webView = Ti.UI.createWebView({ });
window.add(webView);
webView.addScriptMessageHandler(HANDLER_NAME);
webView.addEventListener('message', (e) => {
if (e.name === HANDLER_NAME) {
alert(e.body?.message ?? 'No message');
}
});
window.addEventListener("open", function(){
webView.url = '/page.html'
})
window.open();and <h1>test</h1>
<script>
const androidHandler = window.MyScriptMessageHandler?.postMessage;
const iOSHandler = window.webkit?.messageHandlers?.MyScriptMessageHandler?.postMessage;
document.querySelector("h1").addEventListener("click", function() {
if (androidHandler) {
androidHandler(
JSON.stringify({
name: 'MyScriptMessageHandler',
body: {
message: 'Titanium WebView Rocks!'
},
}),
)
} else if (iOSHandler) {
iOSHandler({
message: 'Titanium WebView Rocks!'
});
} else {
// No app side handlers available.
alert('No app side handler available.')
}
})
</script>and I click on the h1 and get the "no app side..." alert. I've fetch the PR again and rebuild the SDK just to make sure it's running the correct version. Tested liveview and no liveview. But I don't see the correct alert |
|
This example code works now: const HANDLER_NAME = 'MyScriptMessageHandler';
const window = Ti.UI.createWindow({
title: 'Android Script Message'
});
const webView = Ti.UI.createWebView({});
window.add(webView);
window.addEventListener("open", function() {
webView.addScriptMessageHandler(HANDLER_NAME);
webView.addEventListener('message', (e) => {
if (e.name === HANDLER_NAME) {
alert(e.body?.message ?? 'No message');
}
});
webView.url = '/page.html'
})
window.open();
HTML part: <!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<h1>test</h1>
<script>
document.querySelector("h1").addEventListener("click", function() {
const androidHandler = window.MyScriptMessageHandler;
const iOSHandler = window.webkit?.messageHandlers?.MyScriptMessageHandler;
document.querySelector("h1").addEventListener("click", function() {
if (androidHandler) {
androidHandler.postMessage(
JSON.stringify({
name: 'MyScriptMessageHandler',
body: {
message: 'Titanium WebView Rocks!'
},
}),
)
} else if (iOSHandler) {
iOSHandler.postMessage({
message: 'Titanium WebView Rocks!'
});
} else {
// No app side handlers available.
alert('No app side handler available.')
}
})
})
</script>
</body>
</html>(works locally too) |
|
@m1ga Yep! First issue was referencing the Edit: The problem is calling the I've updated the code in description for now, and will check further if we can handle it inside the SDK itself. |
|
@m1ga Just fixed the code (refer description), tested with http://migaweb.de/page.html?123 and our local web page as well. |
|
@janvennemann PR's ready now to proceed further as discussed. |
|
@prashantsaini1 if you click on the text multiple time it will fire the event multiple times |
|
@m1ga It's because your web page code which you posted is adding the event listener again inside the listener itself. ;) |
|
oh 😄 didn't notice the double click event! Then it's working fine now 👍 |
|
First off, thanks a lot @prashantsaini1 for investigating this matter and adding the basic feature parity. This is a great basic start. I'd love to add a unified API for this that does the heavy lifting behind the scenes and does not require so much platform specific extra logic. Right now it is very cumbersome to set up all the required handlers. I'm thinking of a simple event based API that can be used like this inside the web view: window.tiWebViewBridge.emit(eventName: string, data: any)And then on the Titanium side handle it like any other event: webView.addEventListener('my-custom-event', ({ name, data }) => {
console.log({ name, data })
})For this we would use automatically injected JS code that prepares a single script message handler which is used to send the event that we unwrap and forward on the native side into the Titanium event bus. I totally understand this may be out of scope for this PR but i just wanted to leave my two cents how we could improve this with a proper cross-platform API. |
|
for that you can look at #13835 which will inject the current binding.js file in an external page. |
Ah nice, but that is also Android only and is again a totally different API than what iOS uses. That's why i mentioned a unified API that works the same on both platforms. Just to be sure i'm not missing something what's the benefit of this PR compared #13835. Doesn't it practically do the same, e.g. sending events from the web view to the Titanium app. |
|
@janvennemann I just wanted to show you how you could inject the bindings. My old PR will just use the normal You could use that and add a different namespace too but the Ti should stay as many people use that. |
|
@m1ga @janvennemann Well, I found some interesting stuff on iOS. If we enable the I tested it on our web-page and already works fine without the App side: Web page side: Next Steps:
|
|
Ha, thanks @prashantsaini1, you beat me to it. I found the same after digging through our web view implementation thanks to @m1ga's hints. The iOS implementation is also limited to local URLs, by manually invoking I think we should just introduce a new property like |
|
@janvennemann Sounds good. @m1ga I'd take your PR further to enable it for Android as well. :) |
|
sounds good 👍 Not sure if that might be relevant for your page too (in case links that open with target:_blank): #14005 but it can be useful when you work with external pages and you don't want to remove |
|
@m1ga @janvennemann Finally achieved the following syntax for both platforms. To keep backward compatibility without breaking existing iOS apps, added 2nd argument to enable the unified API. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added some notes. The changes in the Web code will make it work on both platforms if you copy and paste it. Otherwise it will complain on Android because webkit is not there and const body is already there.
Co-authored-by: Michael Gangolf <[email protected]>
Co-authored-by: Michael Gangolf <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
ba191e0 to
a4ecd42
Compare

This PR implements the
addScriptMessageHandlerand theremoveScriptMessageHandlermethods for Android platform, bringing parity with the iOS.Titanium App:
Web page: