@capawesome/capacitor-maps-launcher 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/CapawesomeCapacitorMapsLauncher.podspec +17 -0
  2. package/LICENSE +21 -0
  3. package/Package.swift +28 -0
  4. package/README.md +292 -0
  5. package/android/build.gradle +58 -0
  6. package/android/src/main/AndroidManifest.xml +10 -0
  7. package/android/src/main/java/io/capawesome/capacitorjs/plugins/mapslauncher/MapsLauncher.java +200 -0
  8. package/android/src/main/java/io/capawesome/capacitorjs/plugins/mapslauncher/MapsLauncherPlugin.java +117 -0
  9. package/android/src/main/java/io/capawesome/capacitorjs/plugins/mapslauncher/classes/CustomException.java +20 -0
  10. package/android/src/main/java/io/capawesome/capacitorjs/plugins/mapslauncher/classes/CustomExceptions.java +15 -0
  11. package/android/src/main/java/io/capawesome/capacitorjs/plugins/mapslauncher/classes/options/Destination.java +57 -0
  12. package/android/src/main/java/io/capawesome/capacitorjs/plugins/mapslauncher/classes/options/NavigateOptions.java +54 -0
  13. package/android/src/main/java/io/capawesome/capacitorjs/plugins/mapslauncher/classes/results/GetAvailableAppsResult.java +29 -0
  14. package/android/src/main/java/io/capawesome/capacitorjs/plugins/mapslauncher/classes/results/GetDefaultAppResult.java +25 -0
  15. package/android/src/main/java/io/capawesome/capacitorjs/plugins/mapslauncher/interfaces/Callback.java +5 -0
  16. package/android/src/main/java/io/capawesome/capacitorjs/plugins/mapslauncher/interfaces/EmptyCallback.java +5 -0
  17. package/android/src/main/java/io/capawesome/capacitorjs/plugins/mapslauncher/interfaces/NonEmptyResultCallback.java +7 -0
  18. package/android/src/main/java/io/capawesome/capacitorjs/plugins/mapslauncher/interfaces/Result.java +7 -0
  19. package/android/src/main/res/.gitkeep +0 -0
  20. package/dist/docs.json +329 -0
  21. package/dist/esm/definitions.d.ts +195 -0
  22. package/dist/esm/definitions.js +47 -0
  23. package/dist/esm/definitions.js.map +1 -0
  24. package/dist/esm/index.d.ts +4 -0
  25. package/dist/esm/index.js +7 -0
  26. package/dist/esm/index.js.map +1 -0
  27. package/dist/esm/web.d.ts +7 -0
  28. package/dist/esm/web.js +13 -0
  29. package/dist/esm/web.js.map +1 -0
  30. package/dist/plugin.cjs.js +74 -0
  31. package/dist/plugin.cjs.js.map +1 -0
  32. package/dist/plugin.js +77 -0
  33. package/dist/plugin.js.map +1 -0
  34. package/ios/Plugin/Classes/Options/Destination.swift +36 -0
  35. package/ios/Plugin/Classes/Options/NavigateOptions.swift +23 -0
  36. package/ios/Plugin/Classes/Results/GetAvailableAppsResult.swift +16 -0
  37. package/ios/Plugin/Enums/CustomError.swift +36 -0
  38. package/ios/Plugin/Info.plist +24 -0
  39. package/ios/Plugin/MapsLauncher.swift +182 -0
  40. package/ios/Plugin/MapsLauncherPlugin.swift +71 -0
  41. package/ios/Plugin/Protocols/Result.swift +5 -0
  42. package/package.json +94 -0
@@ -0,0 +1,17 @@
1
+ require 'json'
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = 'CapawesomeCapacitorMapsLauncher'
7
+ s.version = package['version']
8
+ s.summary = package['description']
9
+ s.license = package['license']
10
+ s.homepage = package['repository']['url']
11
+ s.author = package['author']
12
+ s.source = { :git => package['repository']['url'], :tag => s.version.to_s }
13
+ s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}'
14
+ s.ios.deployment_target = '15.0'
15
+ s.dependency 'Capacitor'
16
+ s.swift_version = '5.1'
17
+ end
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Robin Genz
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/Package.swift ADDED
@@ -0,0 +1,28 @@
1
+ // swift-tools-version: 5.9
2
+ import PackageDescription
3
+
4
+ let package = Package(
5
+ name: "CapawesomeCapacitorMapsLauncher",
6
+ platforms: [.iOS(.v15)],
7
+ products: [
8
+ .library(
9
+ name: "CapawesomeCapacitorMapsLauncher",
10
+ targets: ["MapsLauncherPlugin"])
11
+ ],
12
+ dependencies: [
13
+ .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "8.0.0")
14
+ ],
15
+ targets: [
16
+ .target(
17
+ name: "MapsLauncherPlugin",
18
+ dependencies: [
19
+ .product(name: "Capacitor", package: "capacitor-swift-pm"),
20
+ .product(name: "Cordova", package: "capacitor-swift-pm")
21
+ ],
22
+ path: "ios/Plugin"),
23
+ .testTarget(
24
+ name: "MapsLauncherPluginTests",
25
+ dependencies: ["MapsLauncherPlugin"],
26
+ path: "ios/PluginTests")
27
+ ]
28
+ )
package/README.md ADDED
@@ -0,0 +1,292 @@
1
+ # @capawesome/capacitor-maps-launcher
2
+
3
+ Capacitor plugin to launch navigation apps with turn-by-turn directions.
4
+
5
+ <div class="capawesome-z29o10a">
6
+ <a href="https://cloud.capawesome.io/" target="_blank">
7
+ <img alt="Deliver Live Updates to your Capacitor app with Capawesome Cloud" src="https://cloud.capawesome.io/assets/banners/cloud-build-and-deploy-capacitor-apps.png?t=1" />
8
+ </a>
9
+ </div>
10
+
11
+ ## Features
12
+
13
+ - 🧭 **Navigate**: Launch a navigation app with turn-by-turn directions to a destination.
14
+ - 🗺️ **Curated apps**: Support for Google Maps, Apple Maps (iOS) and Waze.
15
+ - 📍 **Coordinates & addresses**: Navigate to coordinates or a plain address.
16
+ - 🚗 **Travel modes**: Choose between driving, walking, bicycling and transit (best-effort per app).
17
+ - ✅ **Availability**: Check which navigation apps are installed and can be launched.
18
+ - 📦 **CocoaPods & SPM**: Supports CocoaPods and Swift Package Manager for iOS.
19
+ - 🔁 **Up-to-date**: Always supports the latest Capacitor version.
20
+
21
+ Missing a feature? Just [open an issue](https://github.com/capawesome-team/capacitor-plugins/issues) and we'll take a look!
22
+
23
+ ## Newsletter
24
+
25
+ Stay up to date with the latest news and updates about the Capawesome, Capacitor, and Ionic ecosystem by subscribing to our [Capawesome Newsletter](https://cloud.capawesome.io/newsletter/).
26
+
27
+ ## Compatibility
28
+
29
+ | Plugin Version | Capacitor Version | Status |
30
+ | -------------- | ----------------- | -------------- |
31
+ | 0.x.x | >=8.x.x | Active support |
32
+
33
+ ## Installation
34
+
35
+ You can use our **AI-Assisted Setup** to install the plugin.
36
+ Add the [Capawesome Skills](https://github.com/capawesome-team/skills) to your AI tool using the following command:
37
+
38
+ ```bash
39
+ npx skills add capawesome-team/skills --skill capacitor-plugins
40
+ ```
41
+
42
+ Then use the following prompt:
43
+
44
+ ```
45
+ Use the `capacitor-plugins` skill from `capawesome-team/skills` to install the `@capawesome/capacitor-maps-launcher` plugin in my project.
46
+ ```
47
+
48
+ If you prefer **Manual Setup**, install the plugin by running the following commands and follow the platform-specific instructions below:
49
+
50
+ ```bash
51
+ npm install @capawesome/capacitor-maps-launcher
52
+ npx cap sync
53
+ ```
54
+
55
+ ### Android
56
+
57
+ The plugin declares the required [package visibility](https://developer.android.com/training/package-visibility) `<queries>` for Google Maps and Waze in its own `AndroidManifest.xml`. No additional configuration is required.
58
+
59
+ ### iOS
60
+
61
+ #### Application Queries Schemes
62
+
63
+ To detect and launch Google Maps and Waze, the following URL schemes must be added to the `LSApplicationQueriesSchemes` array in the `Info.plist` file of your app. Without them, `getAvailableApps(...)` reports those apps as unavailable and `navigate(...)` rejects with the `APP_NOT_AVAILABLE` error code.
64
+
65
+ ```xml
66
+ <key>LSApplicationQueriesSchemes</key>
67
+ <array>
68
+ <string>comgooglemaps</string>
69
+ <string>waze</string>
70
+ </array>
71
+ ```
72
+
73
+ Apple Maps is always available and does not require any configuration.
74
+
75
+ ## Configuration
76
+
77
+ No configuration required for this plugin.
78
+
79
+ ## Usage
80
+
81
+ ```typescript
82
+ import { MapsLauncher, NavigationApp } from '@capawesome/capacitor-maps-launcher';
83
+
84
+ const getAvailableApps = async () => {
85
+ const { apps } = await MapsLauncher.getAvailableApps();
86
+ return apps;
87
+ };
88
+
89
+ const getDefaultApp = async () => {
90
+ const { app } = await MapsLauncher.getDefaultApp();
91
+ return app;
92
+ };
93
+
94
+ const navigate = async () => {
95
+ await MapsLauncher.navigate({
96
+ destination: {
97
+ latitude: 37.3349,
98
+ longitude: -122.009,
99
+ },
100
+ app: NavigationApp.GoogleMaps,
101
+ travelMode: 'driving',
102
+ });
103
+ };
104
+
105
+ const navigateToAddress = async () => {
106
+ await MapsLauncher.navigate({
107
+ destination: {
108
+ address: 'Apple Park, Cupertino, CA',
109
+ },
110
+ });
111
+ };
112
+ ```
113
+
114
+ ## API
115
+
116
+ <docgen-index>
117
+
118
+ * [`getAvailableApps()`](#getavailableapps)
119
+ * [`getDefaultApp()`](#getdefaultapp)
120
+ * [`navigate(...)`](#navigate)
121
+ * [Interfaces](#interfaces)
122
+ * [Type Aliases](#type-aliases)
123
+ * [Enums](#enums)
124
+
125
+ </docgen-index>
126
+
127
+ <docgen-api>
128
+ <!--Update the source file JSDoc comments and rerun docgen to update the docs below-->
129
+
130
+ ### getAvailableApps()
131
+
132
+ ```typescript
133
+ getAvailableApps() => Promise<GetAvailableAppsResult>
134
+ ```
135
+
136
+ Get the navigation apps that are installed and can be launched.
137
+
138
+ On iOS, Apple Maps is always included. Google Maps and Waze are only
139
+ included if the corresponding `LSApplicationQueriesSchemes` entries are
140
+ added to the `Info.plist` file of your app.
141
+
142
+ Only available on Android and iOS.
143
+
144
+ **Returns:** <code>Promise&lt;<a href="#getavailableappsresult">GetAvailableAppsResult</a>&gt;</code>
145
+
146
+ **Since:** 0.1.0
147
+
148
+ --------------------
149
+
150
+
151
+ ### getDefaultApp()
152
+
153
+ ```typescript
154
+ getDefaultApp() => Promise<GetDefaultAppResult>
155
+ ```
156
+
157
+ Get the navigation app that is configured as the default handler for
158
+ navigation intents.
159
+
160
+ Returns `null` if the default app is not part of the curated list of
161
+ supported apps or if no default app is set (i.e. the system shows a
162
+ chooser).
163
+
164
+ Only available on Android.
165
+
166
+ **Returns:** <code>Promise&lt;<a href="#getdefaultappresult">GetDefaultAppResult</a>&gt;</code>
167
+
168
+ **Since:** 0.1.0
169
+
170
+ --------------------
171
+
172
+
173
+ ### navigate(...)
174
+
175
+ ```typescript
176
+ navigate(options: NavigateOptions) => Promise<void>
177
+ ```
178
+
179
+ Launch a navigation app with turn-by-turn directions to a destination.
180
+
181
+ If no `app` is provided, the system default behavior is used (a chooser on
182
+ Android, Apple Maps on iOS).
183
+
184
+ Only available on Android and iOS.
185
+
186
+ | Param | Type |
187
+ | ------------- | ----------------------------------------------------------- |
188
+ | **`options`** | <code><a href="#navigateoptions">NavigateOptions</a></code> |
189
+
190
+ **Since:** 0.1.0
191
+
192
+ --------------------
193
+
194
+
195
+ ### Interfaces
196
+
197
+
198
+ #### GetAvailableAppsResult
199
+
200
+ | Prop | Type | Description | Since |
201
+ | ---------- | ---------------------------- | ----------------------------------------------------------- | ----- |
202
+ | **`apps`** | <code>NavigationApp[]</code> | The navigation apps that are installed and can be launched. | 0.1.0 |
203
+
204
+
205
+ #### GetDefaultAppResult
206
+
207
+ | Prop | Type | Description | Since |
208
+ | --------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----- |
209
+ | **`app`** | <code><a href="#navigationapp">NavigationApp</a> \| null</code> | The navigation app that is configured as the default handler. Returns `null` if the default app is not part of the curated list of supported apps or if no default app is set. | 0.1.0 |
210
+
211
+
212
+ #### NavigateOptions
213
+
214
+ | Prop | Type | Description | Default | Since |
215
+ | ----------------- | ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- | ----- |
216
+ | **`app`** | <code><a href="#navigationapp">NavigationApp</a></code> | The navigation app to launch. If not provided, the system default behavior is used (a chooser on Android, Apple Maps on iOS). | | 0.1.0 |
217
+ | **`destination`** | <code><a href="#destination">Destination</a></code> | The destination to navigate to. | | 0.1.0 |
218
+ | **`start`** | <code><a href="#destination">Destination</a></code> | The start location of the route. If not provided, the current location of the device is used. **Note**: The support depends on the selected app. Apple Maps supports it fully, Google Maps opens the directions preview instead of starting turn-by-turn navigation, and Waze ignores it. | | 0.1.0 |
219
+ | **`travelMode`** | <code><a href="#travelmode">TravelMode</a></code> | The travel mode to use for the directions. **Note**: The support depends on the selected app and is best-effort. Waze only supports driving and ignores this option. | <code>'driving'</code> | 0.1.0 |
220
+
221
+
222
+ #### Destination
223
+
224
+ A destination is either defined by its coordinates or by its address, but
225
+ not both.
226
+
227
+ | Prop | Type | Description | Since |
228
+ | --------------- | ------------------- | -------------------------------------------------------------------------------------------------- | ----- |
229
+ | **`address`** | <code>string</code> | The address of the destination. Must be provided without `latitude` and `longitude`. | 0.1.0 |
230
+ | **`latitude`** | <code>number</code> | The latitude of the destination. Must be provided together with `longitude` and without `address`. | 0.1.0 |
231
+ | **`longitude`** | <code>number</code> | The longitude of the destination. Must be provided together with `latitude` and without `address`. | 0.1.0 |
232
+
233
+
234
+ ### Type Aliases
235
+
236
+
237
+ #### TravelMode
238
+
239
+ The travel mode to use for the directions.
240
+
241
+ - `driving`: Driving directions.
242
+ - `walking`: Walking directions.
243
+ - `bicycling`: Bicycling directions.
244
+ - `transit`: Public transit directions.
245
+
246
+ <code>'driving' | 'walking' | 'bicycling' | 'transit'</code>
247
+
248
+
249
+ ### Enums
250
+
251
+
252
+ #### NavigationApp
253
+
254
+ | Members | Value | Description | Since |
255
+ | ---------------- | ------------------------- | ---------------------------------- | ----- |
256
+ | **`AppleMaps`** | <code>'appleMaps'</code> | Apple Maps. Only available on iOS. | 0.1.0 |
257
+ | **`GoogleMaps`** | <code>'googleMaps'</code> | Google Maps. | 0.1.0 |
258
+ | **`Waze`** | <code>'waze'</code> | Waze. | 0.1.0 |
259
+
260
+ </docgen-api>
261
+
262
+ ## Platform Support
263
+
264
+ The behavior of the `navigate(...)` method depends on the selected app and platform. Keep the following in mind:
265
+
266
+ ### Start location
267
+
268
+ | App | `start` support |
269
+ | ----------- | ------------------------------------------------------------------------------------------------------------------ |
270
+ | Apple Maps | Full support. |
271
+ | Google Maps | Supported, but opens the directions preview instead of starting turn-by-turn navigation directly. |
272
+ | Waze | Not supported. The option is ignored. |
273
+
274
+ If `start` is not provided, the current location of the device is used.
275
+
276
+ ### Travel mode
277
+
278
+ | App | `driving` | `walking` | `bicycling` | `transit` |
279
+ | ----------- | --------- | --------- | ----------- | --------- |
280
+ | Apple Maps | ✅ | ✅ | ❌ | ✅ |
281
+ | Google Maps | ✅ | ✅ | ✅ | ✅ |
282
+ | Waze | ✅ | ❌ | ❌ | ❌ |
283
+
284
+ Unsupported travel modes fall back to the default behavior of the respective app. Waze only supports driving and ignores the `travelMode` option.
285
+
286
+ ## Changelog
287
+
288
+ See [CHANGELOG.md](https://github.com/capawesome-team/capacitor-plugins/blob/main/packages/maps-launcher/CHANGELOG.md).
289
+
290
+ ## License
291
+
292
+ See [LICENSE](https://github.com/capawesome-team/capacitor-plugins/blob/main/packages/maps-launcher/LICENSE).
@@ -0,0 +1,58 @@
1
+ ext {
2
+ junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
3
+ androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.1'
4
+ androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.3.0'
5
+ androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.7.0'
6
+ }
7
+
8
+ buildscript {
9
+ repositories {
10
+ google()
11
+ mavenCentral()
12
+ }
13
+ dependencies {
14
+ classpath 'com.android.tools.build:gradle:8.13.0'
15
+ }
16
+ }
17
+
18
+ apply plugin: 'com.android.library'
19
+
20
+ android {
21
+ namespace = "io.capawesome.capacitorjs.plugins.mapslauncher"
22
+ compileSdk = project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 36
23
+ defaultConfig {
24
+ minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 24
25
+ targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 36
26
+ versionCode 1
27
+ versionName "1.0"
28
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
29
+ }
30
+ buildTypes {
31
+ release {
32
+ minifyEnabled false
33
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
34
+ }
35
+ }
36
+ lintOptions {
37
+ abortOnError = false
38
+ }
39
+ compileOptions {
40
+ sourceCompatibility JavaVersion.VERSION_21
41
+ targetCompatibility JavaVersion.VERSION_21
42
+ }
43
+ }
44
+
45
+ repositories {
46
+ google()
47
+ mavenCentral()
48
+ }
49
+
50
+
51
+ dependencies {
52
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
53
+ implementation project(':capacitor-android')
54
+ implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
55
+ testImplementation "junit:junit:$junitVersion"
56
+ androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
57
+ androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
58
+ }
@@ -0,0 +1,10 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ <queries>
3
+ <package android:name="com.google.android.apps.maps" />
4
+ <package android:name="com.waze" />
5
+ <intent>
6
+ <action android:name="android.intent.action.VIEW" />
7
+ <data android:scheme="geo" />
8
+ </intent>
9
+ </queries>
10
+ </manifest>
@@ -0,0 +1,200 @@
1
+ package io.capawesome.capacitorjs.plugins.mapslauncher;
2
+
3
+ import android.content.ActivityNotFoundException;
4
+ import android.content.Context;
5
+ import android.content.Intent;
6
+ import android.content.pm.PackageManager;
7
+ import android.content.pm.ResolveInfo;
8
+ import android.net.Uri;
9
+ import androidx.annotation.NonNull;
10
+ import androidx.annotation.Nullable;
11
+ import io.capawesome.capacitorjs.plugins.mapslauncher.classes.CustomExceptions;
12
+ import io.capawesome.capacitorjs.plugins.mapslauncher.classes.options.Destination;
13
+ import io.capawesome.capacitorjs.plugins.mapslauncher.classes.options.NavigateOptions;
14
+ import io.capawesome.capacitorjs.plugins.mapslauncher.classes.results.GetAvailableAppsResult;
15
+ import io.capawesome.capacitorjs.plugins.mapslauncher.classes.results.GetDefaultAppResult;
16
+ import io.capawesome.capacitorjs.plugins.mapslauncher.interfaces.EmptyCallback;
17
+ import io.capawesome.capacitorjs.plugins.mapslauncher.interfaces.NonEmptyResultCallback;
18
+ import java.util.ArrayList;
19
+ import java.util.List;
20
+
21
+ public class MapsLauncher {
22
+
23
+ public static final String APP_GOOGLE_MAPS = "googleMaps";
24
+ public static final String APP_WAZE = "waze";
25
+ public static final String PACKAGE_GOOGLE_MAPS = "com.google.android.apps.maps";
26
+ public static final String PACKAGE_WAZE = "com.waze";
27
+
28
+ @NonNull
29
+ private final MapsLauncherPlugin plugin;
30
+
31
+ public MapsLauncher(@NonNull MapsLauncherPlugin plugin) {
32
+ this.plugin = plugin;
33
+ }
34
+
35
+ public void getAvailableApps(@NonNull NonEmptyResultCallback<GetAvailableAppsResult> callback) {
36
+ List<String> apps = new ArrayList<>();
37
+ if (isPackageInstalled(PACKAGE_GOOGLE_MAPS)) {
38
+ apps.add(APP_GOOGLE_MAPS);
39
+ }
40
+ if (isPackageInstalled(PACKAGE_WAZE)) {
41
+ apps.add(APP_WAZE);
42
+ }
43
+ callback.success(new GetAvailableAppsResult(apps));
44
+ }
45
+
46
+ public void getDefaultApp(@NonNull NonEmptyResultCallback<GetDefaultAppResult> callback) {
47
+ Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("geo:0,0?q=0,0"));
48
+ ResolveInfo resolveInfo = getContext().getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
49
+ String app = null;
50
+ if (resolveInfo != null && resolveInfo.activityInfo != null) {
51
+ app = mapPackageToApp(resolveInfo.activityInfo.packageName);
52
+ }
53
+ callback.success(new GetDefaultAppResult(app));
54
+ }
55
+
56
+ public void navigate(@NonNull NavigateOptions options, @NonNull EmptyCallback callback) throws Exception {
57
+ String app = options.getApp();
58
+ if (app != null) {
59
+ String packageName = getPackageForApp(app);
60
+ if (packageName == null || !isPackageInstalled(packageName)) {
61
+ throw CustomExceptions.APP_NOT_AVAILABLE;
62
+ }
63
+ }
64
+ Intent intent = createIntent(options);
65
+ try {
66
+ plugin.getActivity().startActivity(intent);
67
+ } catch (ActivityNotFoundException exception) {
68
+ throw CustomExceptions.LAUNCH_FAILED;
69
+ }
70
+ callback.success();
71
+ }
72
+
73
+ @NonNull
74
+ private Intent createDefaultIntent(@NonNull Destination destination) {
75
+ return new Intent(Intent.ACTION_VIEW, Uri.parse("geo:0,0?q=" + Uri.encode(formatDestination(destination))));
76
+ }
77
+
78
+ @NonNull
79
+ private Intent createGoogleMapsIntent(@NonNull Destination destination, @Nullable Destination start, @Nullable String travelMode) {
80
+ Uri uri;
81
+ if (start == null) {
82
+ String value =
83
+ "google.navigation:q=" + Uri.encode(formatDestination(destination)) + "&mode=" + mapTravelModeToGoogleMode(travelMode);
84
+ uri = Uri.parse(value);
85
+ } else {
86
+ String value =
87
+ "https://www.google.com/maps/dir/?api=1" +
88
+ "&origin=" +
89
+ Uri.encode(formatDestination(start)) +
90
+ "&destination=" +
91
+ Uri.encode(formatDestination(destination)) +
92
+ "&travelmode=" +
93
+ mapTravelModeToGoogleUrlMode(travelMode);
94
+ uri = Uri.parse(value);
95
+ }
96
+ Intent intent = new Intent(Intent.ACTION_VIEW, uri);
97
+ intent.setPackage(PACKAGE_GOOGLE_MAPS);
98
+ return intent;
99
+ }
100
+
101
+ @NonNull
102
+ private Intent createIntent(@NonNull NavigateOptions options) {
103
+ String app = options.getApp();
104
+ if (APP_GOOGLE_MAPS.equals(app)) {
105
+ return createGoogleMapsIntent(options.getDestination(), options.getStart(), options.getTravelMode());
106
+ } else if (APP_WAZE.equals(app)) {
107
+ return createWazeIntent(options.getDestination());
108
+ } else {
109
+ return createDefaultIntent(options.getDestination());
110
+ }
111
+ }
112
+
113
+ @NonNull
114
+ private Intent createWazeIntent(@NonNull Destination destination) {
115
+ String query = destination.hasCoordinates() ? "ll=" : "q=";
116
+ String value = "https://waze.com/ul?" + query + Uri.encode(formatDestination(destination)) + "&navigate=yes";
117
+ Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(value));
118
+ intent.setPackage(PACKAGE_WAZE);
119
+ return intent;
120
+ }
121
+
122
+ @NonNull
123
+ private String formatDestination(@NonNull Destination destination) {
124
+ if (destination.hasCoordinates()) {
125
+ return destination.getLatitude() + "," + destination.getLongitude();
126
+ }
127
+ String address = destination.getAddress();
128
+ return address == null ? "" : address;
129
+ }
130
+
131
+ @NonNull
132
+ private Context getContext() {
133
+ return plugin.getContext();
134
+ }
135
+
136
+ @Nullable
137
+ private String getPackageForApp(@NonNull String app) {
138
+ switch (app) {
139
+ case APP_GOOGLE_MAPS:
140
+ return PACKAGE_GOOGLE_MAPS;
141
+ case APP_WAZE:
142
+ return PACKAGE_WAZE;
143
+ default:
144
+ return null;
145
+ }
146
+ }
147
+
148
+ private boolean isPackageInstalled(@NonNull String packageName) {
149
+ try {
150
+ getContext().getPackageManager().getPackageInfo(packageName, 0);
151
+ return true;
152
+ } catch (PackageManager.NameNotFoundException exception) {
153
+ return false;
154
+ }
155
+ }
156
+
157
+ @Nullable
158
+ private String mapPackageToApp(@NonNull String packageName) {
159
+ switch (packageName) {
160
+ case PACKAGE_GOOGLE_MAPS:
161
+ return APP_GOOGLE_MAPS;
162
+ case PACKAGE_WAZE:
163
+ return APP_WAZE;
164
+ default:
165
+ return null;
166
+ }
167
+ }
168
+
169
+ @NonNull
170
+ private String mapTravelModeToGoogleMode(@Nullable String travelMode) {
171
+ if (travelMode == null) {
172
+ return "d";
173
+ }
174
+ switch (travelMode) {
175
+ case "walking":
176
+ return "w";
177
+ case "bicycling":
178
+ return "b";
179
+ case "transit":
180
+ return "l";
181
+ default:
182
+ return "d";
183
+ }
184
+ }
185
+
186
+ @NonNull
187
+ private String mapTravelModeToGoogleUrlMode(@Nullable String travelMode) {
188
+ if (travelMode == null) {
189
+ return "driving";
190
+ }
191
+ switch (travelMode) {
192
+ case "walking":
193
+ case "bicycling":
194
+ case "transit":
195
+ return travelMode;
196
+ default:
197
+ return "driving";
198
+ }
199
+ }
200
+ }