Using Google maps js api with Cordova

Hello, I am developing a project and I need to display maps both on the web and on the mobile side. On the web side, I have successfully displayed the map using Google Maps JS api. However, I encountered certain problems on mobile. The problem with my searches on the internet is that the js api seems to be available with cordova, but for some reason the js api does not load correctly on android. At the moment I am writing this article, there is 3.56.6 version of google maps js api, in this version the web is working correctly, in android this Uncaught (in promise) TypeError: qda.entries is not a function or its return value is not iterable error. This error doesnā€™t make much sense. I downgraded the version a bit to 3.53.14 and this time the map loads, but since I use the marker features, Iā€™m stuck with them. Iā€™ve also looked at plugins for Cordova, but there doesnā€™t seem to be any properly maintained, I donā€™t want to spend that much effort for this. Thanks for your help in advance.

Could you please fetch the WebView version from your Cordova and letā€™s see how we get Cordova to run a WebView that supports ES2020.

I wonder if you can enforce ES2020 for WebView via the modern browser Meteor package.

E.g.

import { setMinimumBrowserVersions } from 'meteor/modern-browsers'
setMinimumBrowserVersions({
  facebook: 325
}, 'minimum versions for ECMAScript 2015 classes')

I think the problem is now known we just need to find a solution: run a WebView version that natively supports ES2020 or later.

Sorry for my late reply. I did some research and experiments on what you wrote. First of all, I would like to give version information about my project.

The project is written with Meteor.js + Svelte.js.

Meteor version: 2.15
Cordova Android Version: 12.0.1

Android phone I use: Mi A3 Android 11
userAgent: Mozilla/5.0 (Linux; Android 11; Mi A3 Build/RKQ1.200903.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/122.0.6261.119 Mobile Safari/537.36

Android emulator I use: Android 12
userAgent: Mozilla/5.0 (Linux; Android 12; sdk_gphone64_arm64 Build/S2B2.211203.006; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/91.0.4472.114 Mobile Safari/537.36

package.json

{
  "dependencies": {
    "@babel/runtime": "^7.20.6",
    "@googlemaps/js-api-loader": "^1.16.6",
    "@material-tailwind/html": "^2.2.2",
    "@sentry/svelte": "^7.108.0",
    "autoprefixer": "^10.4.17",
    "bcrypt": "^5.1.0",
    "cheerio": "^1.0.0-rc.12",
    "classnames": "^2.5.1",
    "daisyui": "^4.7.2",
    "dayjs": "^1.11.9",
    "meteor-node-stubs": "^1.2.5",
    "notiflix": "^3.2.6",
    "postcss": "^8.4.33",
    "postcss-load-config": "^5.0.2",
    "simpl-schema": "^3.4.1",
    "svelte": "^3.54.0",
    "svelte-preprocess": "^5.1.3",
    "tailwindcss": "^3.4.1",
    "tippy.js": "^6.3.7",
    "toastify-js": "^1.12.0"
  },
  "devDependencies": {
    "@types/google.maps": "^3.55.5",
    "@types/jquery": "^3.5.16",
    "@types/toastify-js": "^1.11.1",
    "tinro": "^0.6.12",
    "typescript": "^5.2.2"
  },
  "meteor": {
    "mainModule": {
      "client": "client/main.js"
    },
    "nodeModules": {
      "recompile": {
        "svelte": [
          "legacy"
        ]
      }
    },
    "testModule": "tests/main.js"
  },
  "svelte:compiler": {
    "extensions": [
      "svelte",
      "html"
    ],
    "hydratable": false,
    "css": false
  }
}

versions

accounts-2fa@2.0.2
accounts-base@2.2.10
accounts-password@2.4.0
allow-deny@1.1.1
autoupdate@1.8.0
babel-compiler@7.10.5
babel-runtime@1.5.1
base64@1.0.12
binary-heap@1.0.11
boilerplate-generator@1.7.2
caching-compiler@1.2.2
callback-hook@1.5.1
check@1.3.2
ddp@1.4.1
ddp-client@2.6.1
ddp-common@1.4.0
ddp-rate-limiter@1.2.1
ddp-server@2.7.0
diff-sequence@1.1.2
dynamic-import@0.7.3
ecmascript@0.16.8
ecmascript-runtime@0.8.1
ecmascript-runtime-client@0.12.1
ecmascript-runtime-server@0.11.0
ejson@1.1.3
email@2.2.5
es5-shim@4.8.0
fetch@0.1.4
geojson-utils@1.0.11
hot-code-push@1.0.4
hot-module-replacement@0.5.3
id-map@1.1.1
inter-process-messaging@0.1.1
launch-screen@2.0.0
localstorage@1.2.0
logging@1.3.3
mdg:validated-method@1.3.0
meteor@1.11.5
meteor-base@1.5.1
minifier-css@1.6.4
minifier-js@2.7.5
minimongo@1.9.3
mobile-experience@1.1.1
mobile-status-bar@1.1.0
modern-browsers@0.1.10
modules@0.20.0
modules-runtime@0.13.1
modules-runtime-hot@0.14.2
mongo@1.16.8
mongo-decimal@0.1.3
mongo-dev-server@1.1.0
mongo-id@1.0.8
npm-mongo@4.17.2
ordered-dict@1.1.0
percolate:migrations@1.1.1
promise@0.12.2
random@1.2.1
rate-limit@1.1.1
react-fast-refresh@0.2.8
reactive-dict@1.3.1
reactive-var@1.0.12
reload@1.3.1
retry@1.1.0
routepolicy@1.1.1
sha@1.0.9
shell-server@0.5.0
socket-stream-client@0.5.2
standard-minifier-css@1.9.2
standard-minifier-js@2.8.1
tracker@1.3.3
typescript@4.9.5
underscore@1.6.0
universe:i18n@2.1.0
url@1.3.2
webapp@1.13.8
webapp-hashing@1.1.1
zodern:melte@1.7.0
zodern:melte-compiler@1.4.0
zodern:types@1.0.11

client/main.js

import { Loader } from '@googlemaps/js-api-loader'

Meteor.startup(() => {
  AppUtil.loader = new Loader({
    apiKey: 'API_KEY', // Meteor.settings.public.google[Meteor.isCordova ? 'android' : 'web'].apiKey,
    version: 'weekly',
    libraries: ['geometry', 'places', 'maps', 'marker'],
  })
})

map.svelte


  const initMap = async function () {
    const el = document.getElementById('map')

    if (!el || !AppUtil.loader) {
      loadingOverlay.hide()
      return
    }
    loadingOverlay.show()

    const { Map } = await AppUtil.loader.importLibrary('maps')
    const { PlacesService } = await AppUtil.loader.importLibrary('places')
    const { AdvancedMarkerElement, PinElement } = await AppUtil.loader.importLibrary('marker')

    const map = new Map(el, {
      center: { lat: latitude, lng: longitude },
      zoom: 14,
      mapId: Meteor.settings.public.google.mapId,
    })

...

As far as I understand, we need to support es20 features for cordova. First I searched about changing webview, I found some plugins and some work on this on iOS side but they are not maintained. Then I thought of polyfill (https://polyfill.io/v3/polyfill.js?features=default) but I am not sure if it works properly. Also, I think the code you gave below works only on the server side, I donā€™t understand how I should use it. As a result, I am in a dead end, does this problem exist in cordova other than meteor? Also, cordova has removed node 14 support with version 12.0.1, could this be a conflict on the meteor side? This topic confused me a lot, I apologize for my ridiculous questions.

Ok this version is 3 years old.

I donā€™t know how you got the output of userAgent and I think the output of userAgent might not say much about the WebView used by Cordova. I am thinking you might be able to get the version from the Navigator API of Cordova (similar to Window API in browser) or better from something like this: cordova-plugin-webview-checker - npm

On your device you can check the version of the WebView app on your Android OS in Settings and you can also update it from the store but I do not think this ensures your Cordova will use the same. From this I see new path of research: make sure you have the latest WebView installed on your device and try the Maps. You can also write a ES2020 function in your Meteor startup to have access to test things quickly in your Cordova app.

You can read more about WebView here: What Is Android System WebView, and Is It Safe to Uninstall?.

Could you drop this plugin into your project and see if anything changes: GitHub - ionic-team/cordova-plugin-ionic-webview: Web View plugin for Cordova, specialized for Ionic apps.

It seems both threads (this one and Meteor Android App - Google Map - #16 by perumalkuk) only discuss about Android.

However, we do face the same issue with iOS as well. 3.54 does NOT work on iOS while 3.53 does.

Have you guys tested on iOS too or only Android ?

So far, we have no clue what weā€™re going to do.

Whatā€™s strange is weā€™re testing on Android webview v123 which does support ES2020 and it fails. And for iOS, the version weā€™re using should also support ES2020.

So there seems to be another underlying problem. We still have no clue what weā€™re going to do for May.

At the end of this thread here, @zodern commented on cordovaā€™s build :slight_smile:

He seems to suggest weā€™re stuck with something similar to legacy.

I apologize for my late reply. I didnā€™t have much time for this project due to other things. I checked the webview version using the cordova-plugin-webview-checker you mentioned. As far as I can see, it is the latest version available. I couldnā€™t run the ionic-team/cordova-plugin-ionic-webview package you suggested, which doesnā€™t seem to be very well maintained.

As a result, I think there is an error caused by the Google Maps JS Api not being able to access data in the cordova environment. Since I donā€™t want to spend more time on this right now and Google Maps is not mandatory for the project, I decided to use https://leafletjs.com/. Thank you for your valuable answers.

Android Mi A3:

{
    "packageName": "com.google.android.webview",
    "versionName": "122.0.6261.119",
    "versionCode": 626111933
}

I think I found the problem. Cordova is running at localhost:12976/ by default. When I work at local, I open the ports I work on to the external internet with cloud flare zero trust for webhook or https access. Coincidentally, I noticed this while using cordova-plugin-inappbrowser.

Chrome inspect ss:


Maybe it will lead to a solution.

@receptim : Iā€™m not sure I understand your point and I would like very much to understand. Youā€™re saying it could be network related ? in terms of permissions not given to connect ?

Thereā€™s another path weā€™re going to investigate. Weā€™ve been focusing a lot on the ES2020 thing in Googleā€™s release notes but what if itā€™s related to Array.from (the 3rd in the list).

It seems probable as itā€™s related to the error you posted (and that we also get):

Uncaught (in promise) TypeError: qda.entries is not a function or its return value is not iterable

Now the questions we have:
1-If itā€™s ā€œArray.from()ā€ thatā€™s been overriden. Who did that ?

Cordova ? Both Webviews ? A Meteor Package?

If thatā€™s the case, our options are:
1-Override it again with something that works.
2-Use a different webview (like this one that we have NOT tested: GitHub - ionic-team/cordova-plugin-ionic-webview: Web View plugin for Cordova, specialized for Ionic apps.)
3-Find the module that overrides and ā€¦ ?

Food for thoughts

Actually, what I said is a high probability assumption. The thing is that I have already seen that the device I used in my tests uses the latest webview version. I interpreted this problem as not related to the webview version, but that the google js api cannot access a data that the google js api needs to access when working with cordova and the variable that should be an array remains null or undefined. The two images I threw above actually show this. In one, I logged in from localhost:12976 and there is an error. In the other one I logged in from e.recepozen.com and there is no error and maps loaded.

Of course, I cannot say that the problem is exactly because we do not know where the js api accesses.

A workaround can be done like this. With the cordova-plugin-inappbrowser package, the page with the map is loaded from the main domain.

@receptim Thatā€™s very interesting!

Thanks for the detailed explanation.

So far, our hypothesis that it was Array.from() that did not support iterable does not seem to be true.

We did one test in the console of the cordova based on a test that is done by Google Maps API (weā€™ve read their code):

Unless their API runs another version of Array.from that would come from another library and that would not support iterables, wellā€¦the test seems to show the native Array.from() does support iterables.

So to come back to your point:
-In the network tab of the inspector, I do not see any problem with any network connection being blocked.

How can we find whatā€™s blocking or missing. Thatā€™s what weā€™re going to be sleeping on tonight :wink:

Regards

Hi @receptim,

I was able to reproduce the same behavior as you had :
1-locahost:12491: does not work.
2-https connection to the server: works

Our main hypothesis so far is that localhost works using cordovaā€™s bundle while the network one is the ā€œmodern-browserā€ bundle. The first gives Meteor.isModern === false while the second one gives true.

Cordova bundle would not support loading ES2020 while modern bundle would.

I donā€™t know how to force the modern bundle to all Cordovaā€™s bundle to try it.

1 Like

So there is support for this, but for some reason Meteor.isModern is false on localhost. We need to find out how this changes.

@receptim yes, so far, itā€™s actually only 1 function that fails in the cordova bundle.

See our last post in this thread here: Client Architecture / clientArch / web.browser.legacy - #8 by burni13

Weā€™re a bit skeptical just forcing the modern package like that will have no side effect (mostly on older phones).

So either we try to override the function that fails (not sure yet between Object.entries() or Map.entries() ).

If thereā€™s no easy or risky way, weā€™ll just switch to Leaflet.js until Meteor supports Google Maps in Cordova.

Regards,

Burni13

Ok weā€™ve done more testing:

1-Weā€™ve overridden Object.prototype.entries which fixed this specific error message but then it failed on Object.prototype.keys . So far, weā€™ve stopped working on that.

2-Based on @matheusccastro 's recommendation, weā€™ve downloaded Mapsā€™s JS API 3.56 as a local npm and made it ā€˜compileā€™ by Babel.

This works but it has a serious issue, it could stop working anytime because Google says itā€™s not supported and they donā€™t allow caching for more than 30 minutes. So when it stops working, weā€™ve got to run to build a new version. So itā€™s probably not ā€˜stableā€™ enough to go for prod.

So weā€™ve ended up opening an issue with Meteor :

which seems to be related to another one that was open in January and got no answer at all:

so unless Meteor teams ā€œfixesā€ that bug in Cordovaā€™s bundle, we find another solution, weā€™ll probably have to switch to Leaflet in prod until Meteor supports Google Maps under Cordova again.

Just posting here to confirm that Google Maps is not loading successfully in the legacy bundle of Meteor. Our solution is not to load Google Maps when Meteor.isModern is false and show a message instead. This works for us (on web) as legacy is a small percentage of our users and the use of the maps is not central to the app.

I can see how this is a big issue with cordova given that it loads the legacy bundle. I am not sure if anybody is still around to know why this is the case.

The best route here is to fork Meteor, force modern bundle to cordova and test. That can help give more data for consideration to the Meteor team (who are focused in delivering 3.0)

I havenā€™t develop for cordova for quite a while now but checking the supported android devices, seems like the reason of supporting very old android devices is now moot with the restrictions set for the android api level. I am not sure how it looks like at iOS.

But that might be enough to start supporting the modern bundle for cordova (or at the very least, make it a config).

@rjdavid: would you happen to know where we could make the change (in a fork) to force the modern bundle in cordovaā€™s bundle ?

I donā€™t. The build packages are an excellent place to start