Flutter Deeplink to Google maps and Waze - google-maps

I'm implementing a deeplink to a navigation app (like Google Maps or Waze) from a flutter app. I don't have problems doing so for either Google Maps or Waze, my problem is that if I configure the link for Google Maps, the user can still choose to open it in Waze, but obviously no navigation is started since parameters are different.
Is there a way to limit users choice on the app to use? Or is it possible to use a different link depending on which app the user chooses to open? Or even better, is there a universal link for navigation that works on both apps?

You can force to open the selected application using a Universal link (iOS) / App link (Android) and it should force the selected app to be opened. Of course, If the application you want to launch is not found in the device it will open it in the browser.
Here I assume that you are using latitude and longitude to navigate to the place but you can easily adjust it to something else.
I am also using the url_launcher to launch the links.
void launchWaze(double lat, double lng) async {
var url = 'waze://?ll=${lat.toString()},${lng.toString()}';
var fallbackUrl =
'https://waze.com/ul?ll=${lat.toString()},${lng.toString()}&navigate=yes';
try {
bool launched =
await launch(url, forceSafariVC: false, forceWebView: false);
if (!launched) {
await launch(fallbackUrl, forceSafariVC: false, forceWebView: false);
}
} catch (e) {
await launch(fallbackUrl, forceSafariVC: false, forceWebView: false);
}
}
void launchGoogleMaps(double lat, double lng) async {
var url = 'google.navigation:q=${lat.toString()},${lng.toString()}';
var fallbackUrl =
'https://www.google.com/maps/search/?api=1&query=${lat.toString()},${lng.toString()}';
try {
bool launched =
await launch(url, forceSafariVC: false, forceWebView: false);
if (!launched) {
await launch(fallbackUrl, forceSafariVC: false, forceWebView: false);
}
} catch (e) {
await launch(fallbackUrl, forceSafariVC: false, forceWebView: false);
}
}
You also need to add the following to your Info.plist file:
<key>LSApplicationQueriesSchemes</key>
<array>
<string>googlechromes</string>
<string>comgooglemaps</string>
<string>waze</string>
</array>

Updating to the url_launcher last version
import 'package:url_launcher/url_launcher.dart' as url_launcher;
...
Future<void> launchWazeRoute(double lat, double lng) async {
var url = 'waze://?ll=${lat.toString()},${lng.toString()}';
var fallbackUrl =
'https://waze.com/ul?ll=${lat.toString()},${lng.toString()}&navigate=yes';
try {
bool launched = false;
if (!kIsWeb) {
launched = await url_launcher.launchUrl(Uri.parse(url));
}
if (!launched) {
await url_launcher.launchUrl(Uri.parse(fallbackUrl));
}
} catch (e) {
await url_launcher.launchUrl(Uri.parse(fallbackUrl));
}
}
Future<void> launchGoogleMaps(double lat, double lng) async {
var url = 'google.navigation:q=${lat.toString()},${lng.toString()}';
var fallbackUrl =
'https://www.google.com/maps/search/?api=1&query=${lat.toString()},${lng.toString()}';
try {
bool launched = false;
if (!kIsWeb) {
launched = await url_launcher.launchUrl(Uri.parse(url));
}
if (!launched) {
await url_launcher.launchUrl(Uri.parse(fallbackUrl));
}
} catch (e) {
await url_launcher.launchUrl(Uri.parse(fallbackUrl));
}
}
You also need to put it on info.plist file:
<key>LSApplicationQueriesSchemes</key>
<array>
<string>googlechromes</string>
<string>comgooglemaps</string>
<string>waze</string>
</array>

Related

Chrome Extension embedding script in active web page, in MV3?

beautiful people on the internet. I am new to chrome extension not new to writing code though. I have implemented webpack to use external packages. One major one in my application is npm package by the name "mark.js".
My application works like this i want some specific words to be highlighted in active webpage using this package. I have written code for this to achieve the functionality but the problem is with loading the script in a web page. I have performed different aspect of loading script but that doesnot work. The new MV3 version have some strict rules.
I want to achieve anything similar of loading script in an active webpage. Please help.
btn.addEventListener("click", async () => {
console.log("BUTTON IS PRESSED!!");
try {
await chrome.tabs.query(
{ active: true, currentWindow: true },
async function (tabs) {
chrome.scripting.executeScript({
target: { tabId: tabs[0].id },
func: highlightText,
args: [arr],
});
}
);
} catch (e) {
console.log("ERROR AT CHROME TAB QUERY : ", e);
}
});
async function highlightText(arr) {
console.log(typeof Mark);
try {
var instance2 = new Mark(document.querySelector("body"));
// instance2.mark("is");
var success = [];
// const instance2 = new Mark(document.querySelector("body"));
await Promise.all(
arr.map(async function (obj) {
console.log("OBJECT TEXT : ", obj.text);
instance2.mark(obj.text, {
element: "span",
each: function (ele) {
console.log("STYLING : ");
ele.setAttribute("style", `background-color: ${obj.color};`);
if (obj.title && obj.title != "") {
ele.setAttribute("title", obj.title);
}
ele.innerHTML = obj.text;
success.push({
status: "Success",
text: obj.text,
});
},
});
})
);
console.log("SUCCESS : ", success);
} catch (error) {
console.log(error);
}
}
There's no need to use chrome.runtime.getURL. Since you use executeScript to run your code all you need is to inject mark.js before injecting the function.
Also, don't load popup.js in content_scripts, it's not a content script (these run in web pages), it's a script for your extension page. Actually, you don't need content_scripts at all.
btn.addEventListener('click', async () => {
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
const target = { tabId: tab.id };
const exec = v => (await chrome.scripting.executeScript({ target, ...v }))[0].result;
if (!await exec({ func: () => !!window.Mark })) {
await exec({files: ['mark.js.min'] });
await exec({func: highlightText, args: [arr] });
}
});
For V3 I assume you will want to use Content Scripts in your manifest to inject the javascript into every webpage it matches. I recently open-sourced TorpedoRead and had to do both V2 and V3, I recommend checking the repo as it sounds like I did something similar to you (Firefox is V2, Chrome is V3).
The code below need to be added to your manifest.json and this will execute on every page based on the matches property. You can read more about content scripts here: https://developer.chrome.com/docs/extensions/mv3/content_scripts/
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["yourscript.js"]
}
],

Can we insert two methods in void initState()?

This is dumb question but just for the benefit of the doubt, can we insert two methods in a initState?
E.g:
_getCheckpoint1() async {
var permissions =
await Permission.getPermissionsStatus([PermissionName.Location]);
if (permissions[0].permissionStatus == PermissionStatus.notAgain) {
var askpermissions =
await Permission.requestPermissions([PermissionName.Location]);
} else {
routeCoordinates = await googleMapPolyline.getCoordinatesWithLocation(
origin: LatLng(3.082519, 101.592201),
destination: LatLng(3.083355, 101.589653),
// LatLng(3.082097, 101.585165),
mode: RouteMode.driving);
}
}
_getCheckPoint2() async {
var permissions =
await Permission.getPermissionsStatus([PermissionName.Location]);
if (permissions[0].permissionStatus == PermissionStatus.notAgain) {
var askpermissions =
await Permission.requestPermissions([PermissionName.Location]);
} else {
routeCoordinates = await googleMapPolyline.getCoordinatesWithLocation(
origin: LatLng(3.08171, 101.587507),
destination: LatLng(3.082519, 101.592201),
mode: RouteMode.driving);
}
}
#override
void initState() {
super.initState();
_getCheckpoint1();
_getCheckPoint2();
}
The reason I'm asking is because I want to generate two different polylines and merge them and form a loop of one big route of polyline through Google Maps plugin.
I need help
This is what I intend to do by adding the methods together in an initstate.
I need to construct a set of polylines just as illustrated in the picture
you can define an async function in initState but it should be void, not a future
like that :
void myFutureFunc() async {
await //My Future
}
you can define many functions as you like.

Open Google Maps app if available with flutter

I'm trying to detect whether Google Maps app is installed on iOS, and if so, launch it, if not, launch Apple Maps. Here is what I have so far, but on my phone with Google Maps installed, it isn't detecting it and launching appropriately.
Any ideas?
import 'package:url_launcher/url_launcher.dart';
_launchMaps() async {
String googleUrl =
'comgooglemaps://?center=${trip.origLocationObj.lat},${trip.origLocationObj.lon}';
String appleUrl =
'https://maps.apple.com/?sll=${trip.origLocationObj.lat},${trip.origLocationObj.lon}';
if (await canLaunch("comgooglemaps://")) {
print('launching com googleUrl');
await launch(googleUrl);
} else if (await canLaunch(appleUrl)) {
print('launching apple url');
await launch(appleUrl);
} else {
throw 'Could not launch url';
}
}
I pulled the url scheme from here: How would I be able to open google maps when I press a button in my app?
you can install the packege url_launcher and use the code down below:
import 'package:url_launcher/url_launcher.dart';
class MapUtils {
MapUtils._();
static Future<void> openMap(double latitude, double longitude) async {
String googleUrl = 'https://www.google.com/maps/search/?api=1&query=$latitude,$longitude';
if (await canLaunch(googleUrl)) {
await launch(googleUrl);
} else {
throw 'Could not open the map.';
}
}
}
Now you can open google maps in your app just call this method:
MapUtils.openMap(-3.823216,-38.481700);
I found my issue: this needs to be in the plist file. The code in the question above is fine. (The SO answer referenced in the question only mentioned the "comgooglemaps" string.)
<key>LSApplicationQueriesSchemes</key>
<array>
<string>googlechromes</string>
<string>comgooglemaps</string>
</array>
Docs: https://developers.google.com/maps/documentation/ios-sdk/start#step_7_declare_the_url_schemes_used_by_the_api
Do it this way
Full code is given below
static void navigateTo(double lat, double lng) async {
var uri = Uri.parse("google.navigation:q=$lat,$lng&mode=d");
if (await canLaunch(uri.toString())) {
await launch(uri.toString());
} else {
throw 'Could not launch ${uri.toString()}';
}
}
1) in pubspec.yaml
dependencies:
flutter:
sdk: flutter
...
url_launcher: ^5.7.8
2) Import wherever you want to use
import 'package:url_launcher/url_launcher.dart';
3) final you call
onPressed: () {
navigateTo(location.lat, location.lng);
},
If you don't have the actual latlong, you can simply pass an address to Google Maps.
void launchMap(String address) async {
String query = Uri.encodeComponent(address);
String googleUrl = "https://www.google.com/maps/search/?api=1&query=$query";
if (await canLaunch(googleUrl)) {
await launch(googleUrl);
}
}
Of course, the more information you have in the address, the more accurate the search will be. Exactly the same as looking for something on the actual Google Maps page or app.
By the way, you need to url-encode the address before adding it to the URL, to support special characters like spaces. It's only needed for iOS, but hey, we want to develop for all environments out there.
using url launcher
in yaml file: url_launcher: ^5.0.2 last
then you can use this method to open google maps centered to the provided lat and long
more info to maps intent from docs [here][2]
launchMap({String lat = "47.6", String long = "-122.3"}) async{
var mapSchema = 'geo:$lat,$long';
if (await canLaunch(mapSchema)) {
await launch(mapSchema);
} else {
throw 'Could not launch $mapSchema';
}
}
If you want to navigate with directions you can just create a url with source and destination co-ordinates and other coordinates to add as stops.
Steps:
Install url_launcher plugin
write a code like below.
_launchURL(String url) async {
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
const url ='https://www.google.com/maps/dir/?api=1&origin=43.7967876,-79.5331616&destination=43.5184049,-79.8473993&waypoints=43.1941283,-79.59179|43.7991083,-79.5339667|43.8387033,-79.3453417|43.836424,-79.3024487&travelmode=driving&dir_action=navigate';
_launchURL(url);
static Future<void> openMap(BuildContext context, double lat, double lng) async {
String url = '';
String urlAppleMaps = '';
if (Platform.isAndroid) {
url = 'https://www.google.com/maps/search/?api=1&query=$lat,$lng';
if (await canLaunchUrl(Uri.parse(url))) {
await launchUrl(Uri.parse(url));
} else {
throw 'Could not launch $url';
}
} else {
urlAppleMaps = 'https://maps.apple.com/?q=$lat,$lng';
url = 'comgooglemaps://?saddr=&daddr=$lat,$lng&directionsmode=driving';
if (await canLaunchUrl(Uri.parse(url))) {
await launchUrl(Uri.parse(url));
} else if (await canLaunchUrl(Uri.parse(urlAppleMaps))) {
await launchUrl(Uri.parse(urlAppleMaps));
} else {
throw 'Could not launch $url';
}
}
}
import 'package:url_launcher/url_launcher.dart';
static void launchMapsUrl(
sourceLatitude,
sourceLongitude,
destinationLatitude,
destinationLongitude) async {
String mapOptions = [
'saddr=$sourceLatitude,$sourceLongitude',
'daddr=$destinationLatitude,$destinationLongitude',
'dir_action=navigate'
].join('&');
final url = 'https://www.google.com/maps?$mapOptions';
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
} }
Here you can use this function directly and pass the required parameters and also import this package https://pub.dev/packages/url_launcher/
As follow-up to Roc Boronat's post, the following code can be used for launching the platform specific map application.
Future<void> launchMapUrl(String address) async {
String encodedAddress = Uri.encodeComponent(address);
String googleMapUrl = "https://www.google.com/maps/search/?api=1&query=$encodedAddress";
String appleMapUrl = "http://maps.apple.com/?q=$encodedAddress";
if (Platform.isAndroid) {
try {
if (await canLaunch(googleMapUrl)) {
await launch(googleMapUrl);
}
} catch (error) {
throw("Cannot launch Google map");
}
}
if (Platform.isIOS) {
try {
if (await canLaunch(appleMapUrl)) {
await launch(appleMapUrl);
}
} catch (error) {
throw("Cannot launch Apple map");
}
}
For more information regarding the query parameters in Apple Maps URL, please visit this link.
Edit (7th Aug, 2022): This code will work upto version 6.0.20 of the url_launcher plugin. I could not get it to work after this version as I was getting an ERR_UNKNOWN_URL_SCHEME error when trying to launch Google Maps using canLaunchUrl and launchUrl methods using the versions of the plugin above 6.0.20 and 6.0.20. It works only with the deprecated methods (canLaunch and launch). Just a heads up if anyone wants to try this code snippet.
with 'url_launcher 6.1.0' + physical address instead of lat & lon,
void _pushMap(String address) async {
String query = Uri.encodeComponent(address);
String googleUrl = "google.navigation:q=$query";
Uri googleUri = Uri.parse(googleUrl);
if (await canLaunchUrl(googleUri)) {
await launchUrl(googleUri);
}
}
This will send an implicit Intent to open related apps including google maps.
Haven't tested on iOS devices.
tldr: I think there's an error in the library and canLaunch sometimes returns false even if the url can be launched.
I was trying to open a google maps link (https://goo.gl/maps/mHGzrGUhUHrQByAm8) the same way I do for another link from my app, but for whatever reason canLaunch always returned false.
So now I launch in a try catch block to make sure it doesn't crash my app, and it's working.
try {
launch(url);
} catch (error, stack) {
// log error
}
you can install the packege url_launcher and use the code down below:
This is the latest code as per
url_launcher: 6.1.6
canLaunch();
launch(); these methods has been deprecated now.
class GoogleMapUtils {
GoogleMapUtils._();
static Future<void> openMapApp(double latitude, double longitude) async {
Uri googleUrl = Uri.parse('https://www.google.com/maps/search/?api=1&query=$latitude,$longitude');
if (await canLaunchUrl(googleUrl)) {
await launchUrl(googleUrl);
} else {
throw 'Unable open the map.';
}
}
}
Use plugin:
intent: ^1.4.0
Try the following code:
static void navigateTo(double lat, double lng) async {
var uri = Uri.parse("google.navigation:q=$lat,$lng&mode=c");
android_intent.Intent()
..setAction(android_action.Action.ACTION_VIEW)
..setData(uri)
..setPackage("com.google.android.apps.maps")
..startActivity().catchError((e) => print(e));
}
Note: Only works on Android devices
Install url_launcher package
use the below function
void launchMap() async {
Uri googleUrl = Uri.parse('https://www.google.com/maps/search/?api=1&query=Googleplex');
if (await canLaunchUrl(googleUrl)) {
await launchUrl(googleUrl, mode:LaunchMode.externalApplication);
}
}
Using url luncher with navigation open by default.
Sample code - if app installed it will open in app otherwise open in any browser
///launch map
Future<void> openMap(double latitude, double longitude) async {
String mapUrl = '';
if (Platform.isIOS) {
mapUrl =
'https://maps.apple.com/?daddr=$latitude,$longitude';
} else {
mapUrl =
'https://www.google.com/maps/dir/?api=1&destination=$latitude,$longitude&travelmode=driving';
}
if (await canLaunchUrl(Uri.parse(mapUrl))) {
await launchUrl(Uri.parse(mapUrl),mode: LaunchMode.externalApplication);
} else {
throw 'Could not open the map.';
}
}
if you like to open google map in apple devices add this code in info.plist
<key>LSApplicationQueriesSchemes</key>
<array>
<string>googlechromes</string>
<string>comgooglemaps</string>
</array>
<key>LSApplicationQueriesSchemes</key>
For other queries
Google url params example
https://www.google.com/maps/dir/?api=1
&origin=$latitude,$longitude
&destination=$latitude,$longitude
&travelmode=driving
&dir_action=navigate
Apple
q= query
saddr = starting point for directions
daddr = destination point for directions
dirflg = The transport type

Chrome Extension Redirection

Hi i did a Chrome extension who block urls, actually when a url is blocked a white page come and show a messagen i would like to do a redirection instead to google.com.
this is my actual code of background.js:
(function() {
var AUTHORIZED_DOMAINS= {
"www.badurl.com": false,
"badurl.com": false
};
function extract_domain(url) {
var matches = url.match(/^https?\:\/\/([^\/?#]+)(?:[\/?#]|$)/i);
return matches[1];
}
chrome.webRequest.onBeforeRequest.addListener(function(details) {
var domain = extract_domain(details.url);
return { cancel: AUTHORIZED_DOMAINS[domain ]===false };
}, {urls: ["<all_urls>"]},["blocking"]);})();
instead of returning { cancel: ... } in the listener, let's just use the tabs API:
chrome.tabs.update({
url: "http://www.google.com/"
});
Note: tabs permission is required

Geolocation in Flash

I'm building a small web app in Flash. Is there a solution to get the geo-location of a user?
The easiest way is to interface with a JavaScript function.
In your HTML:
<script>
function getGEO()
{
// First check if your browser supports the geolocation API
if (navigator.geolocation)
{
//alert("HTML 5 is getting your location");
// Get the current position
navigator.geolocation.getCurrentPosition(function(position)
{
lat = position.coords.latitude
long = position.coords.longitude;
// Pass the coordinates to Flash
passGEOToSWF(lat, long);
});
} else {
//alert("Sorry... your browser does not support the HTML5 GeoLocation API");
}
}
function passGEOToSWF(lat,long)
{
//alert("HTML 5 is sending your location to Flash");
// Pass the coordinates to mySWF using ExternalInterface
document.getElementById("index").passGEOToSWF(lat,long);
}
</script>
Then, in your Application, once your map is ready, put this in a function:
//for getting a user's location
if (ExternalInterface.available)
{
//check if external interface is available
try
{
// add Callback for the passGEOToSWF Javascript function
ExternalInterface.addCallback("passGEOToSWF", onPassGEOToSWF);
}
catch (error:SecurityError)
{
// Alert the user of a SecurityError
}
catch (error:Error)
{
// Alert the user of an Error
}
}
Finally, have a private function ready to catch the callback.
private function onPassGEOToSWF(lat:*,long:*):void
{
userLoc = new LatLng(lat,long);
map.setCenter(userLoc);
}