Specs:
PhoneGap Desktop App v0.4.3
Android v5.1.1
The above code is working fine with Desktop app, and the config.xml is created by that PhoneGap Desktop App.
And when i tried it on build.phonegap.com, Google maps failed to initialize, so, nothing appears on android, just a white screen.
Here is my initMap method which the API needs:
var map, directionsService, directionsDisplay;
function initMap() {
directionsService = new google.maps.DirectionsService;
directionsDisplay = new google.maps.DirectionsRenderer;
map = new google.maps.Map(document.getElementById('gMap'), {
zoom: 10,
center: { lat: 25.0115052, lng: 66.7845126 },
mapTypeId: 'roadmap',
});
directionsDisplay.setMap(map);
} // initMap() ends
config.xml:
<?xml version='1.0' encoding='utf-8'?>
<widget id="com.phonegap.helloworld"
version="1.0.0"
xmlns="http://www.w3.org/ns/widgets"
xmlns:gap="http://phonegap.com/ns/1.0">
<name>TestApp</name>
<description>
A blank PhoneGap app.
</description>
<author email="support#phonegap.com" href="http://phonegap.com">
PhoneGap Team
</author>
<content src="index.html" />
<access origin="*" />
</widget>
Following are the points which are necessary to remember while making native hybrid apps:
Version support of Web Languages (HTML, CSS, JS, ...) in the targeted device (Android, IOS, etc).
Load the required plugin / libraries to work with native components.
Solution:
you need cordova-plugin-whitelist plugin to access the maps, so, that will solve your problem:
<plugin name="cordova-plugin-whitelist" spec="1.3.2" />
<!-- Allow geo: links to open maps -->
<allow-intent href="geo:*" />
According to Cordova Docs:
By default, no external URLs are allowed. On Android, this equates to sending an intent of type BROWSEABLE.
Related
Dynamic link is not opening the installed mobile app. It opens the Play Store instead. I have a button on my website on click of which, I want to open my app. For this, I am opening a dynamic link on click of that button on my website. When I click on the button, in some web browsers, the dynamic link is redirecting to Google Play store app(with my app on the Play Store) and in some browsers, opening Play Store website(with my app on the Play Store) inside the browser. However, when I send that dynamic link in the chat apps like Whatsapp and click on that link from the chat, then its opening my installed application.
I have also uploaded the release and debug SHA-256 keys from my local machine and the Google Play Store on the Firebase Console.
I have gone through several Github issues and stackoverflow questions, but could not find any solution for it.
Mobile
On mobile side, I have dynamic link listeners setup. We are generating the dynamic link on the backend side(code included below).
useEffect(() => {
getInitialDynamicLink();
const unsubscribe = dynamicLinks().onLink(handleDynamicLink);
return () => unsubscribe();
}, []);
const handleDynamicLink = link => {
if (link?.url) {
console.log('shared url is: ', link?.url);
}
};
const getInitialDynamicLink = () => {
dynamicLinks()
.getInitialLink()
.then(link => {
handleDynamicLink(link);
});
};
Backend
On the backend, I am using https://www.npmjs.com/package/firebase-dynamic-links/v/1.0.0 to generate dynamic links.
package.json:
"#react-native-firebase/app": "^16.4.0",
"#react-native-firebase/dynamic-links": "^16.4.0",
"react-native": "0.67.4",
android/build.gradle
ext {
buildToolsVersion = "31.0.0"
minSdkVersion = 21
compileSdkVersion = 33
targetSdkVersion = 33
ndkVersion = "21.4.7075529"
kotlin_version = "1.4.0"
googlePlayServicesAuthVersion = "19.2.0"
}
AndroidManifest.xml:
As mentioned in the doc https://developer.android.com/training/app-links#android-app-links, my app also has the App Link
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:host="appname.page.link" android:scheme="https"/>
</intent-filter>
i am using bing maps with asp .net. i want to track multiple users ( drivers ) . i found a demo on how to track a user in bing website but i didn't figure out how to track specific user with specific id. here is the code to track user
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8" />
<script type='text/javascript'>
var map, watchId, userPin;
function GetMap()
{
map = new Microsoft.Maps.Map('#myMap', {
credentials: ‘Your Bing Maps Key’
});
}
function StartTracking() {
//Add a pushpin to show the user's location.
userPin = new Microsoft.Maps.Pushpin(map.getCenter(), { visible: false });
map.entities.push(gpsPin);
//Watch the users location.
watchId = navigator.geolocation.watchPosition(UsersLocationUpdated);
}
function UsersLocationUpdated(position) {
var loc = new Microsoft.Maps.Location(
position.coords.latitude,
position.coords.longitude);
//Update the user pushpin.
userPin.setLocation(loc);
userPin.setOptions({ visible: true });
//Center the map on the user's location.
map.setView({ center: loc });
}
function StopTracking() {
// Cancel the geolocation updates.
navigator.geolocation.clearWatch(watchId);
//Remove the user pushpin.
map.entities.clear();
}
</script>
<script type='text/javascript' src='http://www.bing.com/api/maps/mapcontrol?callback=GetMap' async defer></script>
</head>
<body>
<div id="myMap" style="position:relative;width:600px;height:400px;"></div><br/>
<input type="button" value="Start Continuous Tracking" onclick="StartTracking()" />
<input type="button" value="Stop Continuous Tracking" onclick="StopTracking()"/>
</body>
</html>
The code you provided will show the user where they are on the map. If you want to see the location of multiple drivers on a map, you will need to capture the location of each driver from a device and get that data into a backend service, then have that backend service send the data to the frontend map canvas (i.e. Bing Maps). There are a lot of different ways to do this.
First you need to know how you are going to capture the drivers location. Two common methods:
A mobile app that uses the native geolocation APIs in the background and sends updates to the backend service.
A dedicated IoT device that is either connected to the vehicle or in the vehicle.
A really quick way to do this is to leverage Azure IoT hub for the backend service and IoT central for the frontend. Here is a reference architecture: https://learn.microsoft.com/en-us/azure/architecture/solution-ideas/articles/real-time-asset-tracking-mgmt-iot-central
Bing maps has an open-source project that leverages mobile devices and displays the data on a map: https://github.com/Microsoft/Bing-Maps-Fleet-Tracker
I tried to use firebase auth on the app, it runs fine on android emu and able to create account and login but not on web(chrome). When I run the debug it gave an error of TypeError: Cannot read properties of undefined (reading 'app'). But if I run flutter build web --release and open the web link it returns
ReferenceError: firebase is not defined. I have been google-ing for days, still unable to fix this issue. I'm at the dead-end not sure what to do. the const firebaseConfig = {...}; in the index.html was given from firebase auth when created an webapp project.
Please help. not sure where it went wrong.
flutter doctor
[√] Flutter (Channel stable, 2.5.0, on Microsoft Windows [Version 10.0.22454.1000],locale
en-US)
[√] Android toolchain - develop for Android devices (Android SDK version 31.0.0)
[√] Chrome - develop for the web
[√] Android Studio (version 2020.3)
[√] VS Code (version 1.60.2)
[√] Connected device (2 available)
flutter --version
Flutter 2.5.0 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 4cc385b4b8 (2 weeks ago) • 2021-09-07 23:01:49 -0700
Engine • revision f0826da7ef
Tools • Dart 2.14.0
in the pupspec.yaml
name: login_test
description: A new Flutter project.
publish_to: 'none'
version: 1.0.0+1
environment:
sdk: ">=2.12.0 <3.0.0"
dependencies:
cupertino_icons: ^1.0.2
firebase_auth: ^3.1.1
firebase_core: ^1.6.0
flutter:
sdk: flutter
fluttertoast: ^8.0.8
form_field_validator: ^1.1.0
dev_dependencies:
flutter_lints: ^1.0.0
flutter_test:
sdk: flutter
flutter:
uses-material-design: true
in the web/index.html
<!DOCTYPE html>
<html>
<head>
<!--
If you are serving your web app in a path other than the root, change the
href value below to reflect the base path you are serving from.
The path provided below has to start and end with a slash "/" in order for
it to work correctly.
For more details:
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
This is a placeholder for base href that will be replaced by the value of
the `--base-href` argument provided to `flutter build`.
-->
<base href="$FLUTTER_BASE_HREF">
<meta charset="UTF-8">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
<meta name="description" content="A new Flutter project.">
<!-- iOS meta tags & icons -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="login_test">
<link rel="apple-touch-icon" href="icons/Icon-192.png">
<title>login_test</title>
<link rel="manifest" href="manifest.json">
</head>
<body>
<!-- Firebase Configuration -->
<script type="module">
// Import the functions you need from the SDKs you need
import { initializeApp } from "https://www.gstatic.com/firebasejs/9.0.2/firebase-app.js";
// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries
import { auth } from "https://www.gstatic.com/firebasejs/9.0.2/firebase-auth.js"
// Your web app's Firebase configuration
const firebaseConfig = {
apiKey: "_________-_________",
authDomain: "_________-_________.firebaseapp.com",
projectId: "_________-_________",
storageBucket: "_________-_________.appspot.com",
messagingSenderId: "_________",
appId: "1:_________:web:_________"
};
// Initialize Firebase
const app = initializeApp(firebaseConfig);
</script>
<!-- This script installs service_worker.js to provide PWA functionality to
application. For more information, see:
https://developers.google.com/web/fundamentals/primers/service-workers -->
<script>
var serviceWorkerVersion = null;
var scriptLoaded = false;
function loadMainDartJs() {
if (scriptLoaded) {
return;
}
scriptLoaded = true;
var scriptTag = document.createElement('script');
scriptTag.src = 'main.dart.js';
scriptTag.type = 'application/javascript';
document.body.append(scriptTag);
}
if ('serviceWorker' in navigator) {
// Service workers are supported. Use them.
window.addEventListener('load', function () {
// Wait for registration to finish before dropping the <script> tag.
// Otherwise, the browser will load the script multiple times,
// potentially different versions.
var serviceWorkerUrl = 'flutter_service_worker.js?v=' + serviceWorkerVersion;
navigator.serviceWorker.register(serviceWorkerUrl)
.then((reg) => {
function waitForActivation(serviceWorker) {
serviceWorker.addEventListener('statechange', () => {
if (serviceWorker.state == 'activated') {
console.log('Installed new service worker.');
loadMainDartJs();
}
});
}
if (!reg.active && (reg.installing || reg.waiting)) {
// No active web worker and we have installed or are installing
// one for the first time. Simply wait for it to activate.
waitForActivation(reg.installing || reg.waiting);
} else if (!reg.active.scriptURL.endsWith(serviceWorkerVersion)) {
// When the app updates the serviceWorkerVersion changes, so we
// need to ask the service worker to update.
console.log('New service worker available.');
reg.update();
waitForActivation(reg.installing);
} else {
// Existing service worker is still good.
console.log('Loading app from service worker.');
loadMainDartJs();
}
});
// If service worker doesn't succeed in a reasonable amount of time,
// fallback to plaint <script> tag.
setTimeout(() => {
if (!scriptLoaded) {
console.warn(
'Failed to load app from service worker. Falling back to plain <script> tag.',
);
loadMainDartJs();
}
}, 4000);
});
} else {
// Service workers not supported. Just drop the <script> tag.
loadMainDartJs();
}
</script>
<script src="main.dart.js" type="application/javascript"></script>
</body>
</html>
I think that I got what's happening. The problem is to integrate Flutter compiled to web with Firebase web api.
The FlutterFire (it is the Flutter library to integrate with Firebase) was developed to integrate with the Firebase web api version 8.6.1.
On the other hand, Firebase web api is already in version 9.x, and it has different method calls on initialization. So, the solution is to use Flutter web api 8.6.1 instead of 9.x like de Flutter web api documentation.
The confusion comes from when a beginner create a new Firebase app at the console and the page gives a code to put on the flutter web index.html, but in this case the code use Firebase web api 9.x version style.
TL;DR;
The code in the Flutter web/index.html needs to be exactly like this. Put in the beginning of the body tag. Just replace your firebaseConfig object.
<script src="https://www.gstatic.com/firebasejs/8.6.1/firebase-app.js"></script>
<script>
var firebaseConfig = {
apiKey: "----",
authDomain: "----",
projectId: "----",
storageBucket: "----",
messagingSenderId: "----",
appId: "----"
};
firebase.initializeApp(firebaseConfig);
</script>
Use this libraries but replace the version to 8.6.1.
You should really follow the official docs. If you follow it from the start carefully it will take you there. You'll occasionally see web-specific stuff like this:
https://firebase.flutter.dev/docs/installation/web
https://firebase.flutter.dev/docs/firestore/overview#3-web-only-add-the-sdk
We use it in Flutter Web just fine using these instructions. Your index.html looks different from what's there in the docs. You probably followed a tutorial somewhere that is probably outdated now.
I use one nuxt instance to serve several domains with different languages. For each domain I use a different Google-Tag-Manager account.
Within nuxtServerInit I add to the store the hostname and also the Google-Tag-Manager ID.
Now I am looking for a way to add the Javascript snippets to my nuxt project.
This one needs to be in the head
<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXX);</script>
<!-- End Google Tag Manager -->
And that one at the beginning of the body
<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXX"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->
My first idea is it to add this code programmatically to the document, but I don't know how.
Any suggestions or better idea to accomplish this?
I already tried to use the community solution. But it does not support different ID's.
Can anyone help implementing Nuxt.js Google Tag Manager with function based id
The main problem of this solution is the module which is used itself. A module is only called once but it needed to be something else to be called on each request.
This question is similar and helped me find the answer to this one.
Create a new plugin at plugins/gtm.js (or whatever you want to name it):
// plugins/gtm.js
let gtmKey;
// In this example I care about the page title but you can use other properties if you'd like
switch(document.title) {
case 'Title 1':
gtmKey = 'GTM-XXXXXX1';
break;
case 'Title 2':
gtmKey = 'GTM-XXXXXX2';
break;
default:
break;
}
export default () => {
if (!gtmKey) { // In case I have other pages not in the switch statement above
return;
}
/*
** Include Google Tag Manager
*/
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer', gtmKey);
}
Then load it in from nuxt.config.js:
// nuxt.config.js
export default {
...
plugins: [{ src: '~/plugins/gtm.js', mode: 'client' }],
...
}
Note 1: I don't really like how I've hardcoded the titles into this plugin since an update of the title on one of my pages could break this without me knowing. Suggestions here are welcome.
Note 2: My eslint was complaining about no semicolon before the core GTM closure (just before the (function...) so I actually just disabled eslint for this whole file with // eslint-disable. You could just disable it for the line.
I am using asp.net bundling / minification and putting everything in bundle.config like this:
<styleBundle path="~/css/css">
<include path="~/css/bootstrap.css" />
<include path="~/css/flexslider.css" />
<include path="~/css/font-awesome.css" />
<include path="~/css/Site.css" />
<include path="~/css/orange.css" />
</styleBundle>
But I would like to use bootstrap.css from a CDN:
//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css
So how can we do this in the bundle.config?
Currently you cannot mix and match and pull some of the files in your bundle from an external source like a cdn. You could upload the entire bundle to a CDN and configure the helpers to render a reference to the bundle in a CDN, but you cannot include files from external sources, the files must live somewhere that your app can find.
You could work around this by implementing a VirtualPathProvider that was able to fetch files from your CDN at runtime, but you would have to build that yourself.
The ASP.NET documentation may be able to help you out - http://www.asp.net/mvc/tutorials/mvc-4/bundling-and-minification, there is a section called Using a CDN.
You cannot mix bundles, but you can include an outside source in your boundle config.
Here es an example picked from here as randomidea pointed out.
public static void RegisterBundles(BundleCollection bundles)
{
//bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
// "~/Scripts/jquery-{version}.js"));
bundles.UseCdn = true; //enable CDN support
//add link to jquery on the CDN
var jqueryCdnPath = "http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.1.min.js";
bundles.Add(new ScriptBundle("~/bundles/jquery",
jqueryCdnPath).Include(
"~/Scripts/jquery-{version}.js"));
// Code removed for clarity.
}
We need to enable CDN, to do so we set UseCdn to true and we add the url in the ScriptBundle constructor. The include file is going to be used in debug mode.
As the article suggest, we need to have a fallback mechanism in case our CDN fail:
#Scripts.Render("~/bundles/jquery")
<script type="text/javascript">
if (typeof jQuery == 'undefined') {
var e = document.createElement('script');
e.src = '#Url.Content("~/Scripts/jquery-1.7.1.js")';
e.type = 'text/javascript';
document.getElementsByTagName("head")[0].appendChild(e);
}
</script>
Hope this helps.