diff --git a/README.md b/README.md index 8e6d0bf9..d62831e3 100644 --- a/README.md +++ b/README.md @@ -295,6 +295,11 @@ Array that contains the longitude and latitude for the starting point.
Array that contains the longitude and latitude for the destination point.
`[$longitude, $latitude]` +#### `waypoints` + +Array that contains arrays of longitude and latitude for the waypoints (limit 25 as per the MapBox restrictions).
+`[[$longitude, $latitude], [$longitude, $latitude]]` + #### `shouldSimulateRoute` Boolean that controls route simulation. Set this as `true` to auto navigate which is useful for testing or demo purposes. Defaults to `false`. @@ -311,6 +316,18 @@ Boolean that toggles voice instructions. Defaults to `false`. Boolean that controls showing the `StatusView` (iOS only). This is the transparent black bar with the "Simulating Navigation" text shown in the above screenshot. Defaults to `false`. +#### `vehicleMaxWidth` + +Number that sets max width (in meters) of the vehicle. Defaults to `1.6`. + +#### `vehicleMaxHeight` + +Number that sets max height (in meters) of the vehicle. Defaults to `1.9`. + +#### `mute` + +Boolean that toggles voice instructions. Defaults to `false`. + #### `onLocationChange` Function that is called frequently during route navigation. It receives `latitude` and `longitude` as parameters that represent the current location during navigation. diff --git a/android/build.gradle b/android/build.gradle index 181e82ce..0d5e44b9 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,167 +1,99 @@ -// android/build.gradle - -// based on: -// -// * https://github.com/facebook/react-native/blob/0.60-stable/template/android/build.gradle -// original location: -// - https://github.com/facebook/react-native/blob/0.58-stable/local-cli/templates/HelloWorld/android/build.gradle -// -// * https://github.com/facebook/react-native/blob/0.60-stable/template/android/app/build.gradle -// original location: -// - https://github.com/facebook/react-native/blob/0.58-stable/local-cli/templates/HelloWorld/android/app/build.gradle - -// https://www.cognizantsoftvision.com/blog/creating-an-android-native-module-for-react-native/ - -def DEFAULT_COMPILE_SDK_VERSION = 31 -def DEFAULT_BUILD_TOOLS_VERSION = '30.0.2' -def DEFAULT_MIN_SDK_VERSION = 21 -def DEFAULT_TARGET_SDK_VERSION = 31 - -def safeExtGet(prop, fallback) { - rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback -} - -apply plugin: 'com.android.library' -apply plugin: 'kotlin-android' -apply plugin: 'maven' - buildscript { - ext.kotlin_version = '1.5.21' - // The Android Gradle plugin is only required when opening the android folder stand-alone. - // This avoids unnecessary downloads and potential conflicts when the library is included as a - // module dependency in an application project. - // ref: https://docs.gradle.org/current/userguide/tutorial_using_tasks.html#sec:build_script_external_dependencies - if (project == rootProject) { - repositories { - google() - jcenter() - } - dependencies { - classpath 'com.android.tools.build:gradle:4.2.2' - } - } + // Buildscript is evaluated before everything else so we can't use getExtOrDefault + def kotlin_version = rootProject.ext.has("kotlinVersion") ? rootProject.ext.get("kotlinVersion") : project.properties["MapboxNavigation_kotlinVersion"] - repositories { - mavenCentral() - } + repositories { + google() + mavenCentral() + } + + dependencies { + classpath "com.android.tools.build:gradle:7.2.2" + // noinspection DifferentKotlinGradleVersion + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} - dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } +def isNewArchitectureEnabled() { + return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true" } -apply plugin: 'com.android.library' -apply plugin: 'kotlin-android' -apply plugin: 'maven' +apply plugin: "com.android.library" +apply plugin: "kotlin-android" -android { - compileSdkVersion safeExtGet('compileSdkVersion', DEFAULT_COMPILE_SDK_VERSION) - buildToolsVersion safeExtGet('buildToolsVersion', DEFAULT_BUILD_TOOLS_VERSION) - defaultConfig { - minSdkVersion safeExtGet('minSdkVersion', DEFAULT_MIN_SDK_VERSION) - targetSdkVersion safeExtGet('targetSdkVersion', DEFAULT_TARGET_SDK_VERSION) - versionCode 1 - versionName "1.0" - } - lintOptions { - abortOnError false - } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - kotlinOptions { - jvmTarget = "1.8" - } - buildFeatures { - viewBinding true - } -} -repositories { - // ref: https://www.baeldung.com/maven-local-repository - mavenLocal() - maven { - // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm - url "$rootDir/../node_modules/react-native/android" - } - maven { - // Android JSC is installed from npm - url "$rootDir/../node_modules/jsc-android/dist" - } - google() - jcenter() +def appProject = rootProject.allprojects.find { it.plugins.hasPlugin('com.android.application') } + +if (isNewArchitectureEnabled()) { + apply plugin: "com.facebook.react" } -dependencies { - //noinspection GradleDynamicVersion - implementation 'com.facebook.react:react-native:+' // From node_modules - implementation "com.mapbox.navigation:android:2.1.1" - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation 'androidx.constraintlayout:constraintlayout:2.0.4' - implementation 'androidx.cardview:cardview:1.0.0' +def getExtOrDefault(name) { + return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["MapboxNavigation_" + name] } -def configureReactNativePom(def pom) { - def packageJson = new groovy.json.JsonSlurper().parseText(file('../package.json').text) - - pom.project { - name packageJson.title - artifactId packageJson.name - version = packageJson.version - group = "com.homee.mapboxnavigation" - description packageJson.description - url packageJson.repository.baseUrl - - licenses { - license { - name packageJson.license - url packageJson.repository.baseUrl + '/blob/master/' + packageJson.licenseFilename - distribution 'repo' - } - } - } +def getExtOrIntegerDefault(name) { + return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["MapboxNavigation_" + name]).toInteger() } -afterEvaluate { project -> - // some Gradle build hooks ref: - // https://www.oreilly.com/library/view/gradle-beyond-the/9781449373801/ch03.html - task androidJavadoc(type: Javadoc) { - source = android.sourceSets.main.java.srcDirs - classpath += files(android.bootClasspath) - classpath += files(project.getConfigurations().getByName('compile').asList()) - include '**/*.java' - } +android { + compileSdkVersion getExtOrIntegerDefault("compileSdkVersion") - task androidJavadocJar(type: Jar, dependsOn: androidJavadoc) { - from androidJavadoc.destinationDir + defaultConfig { + minSdkVersion getExtOrIntegerDefault("minSdkVersion") + targetSdkVersion getExtOrIntegerDefault("targetSdkVersion") + buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() + } + buildTypes { + release { + minifyEnabled false } + } - task androidSourcesJar(type: Jar) { - from android.sourceSets.main.java.srcDirs - include '**/*.java' - } + lintOptions { + disable "GradleCompatible" + } - android.libraryVariants.all { variant -> - def name = variant.name.capitalize() - def javaCompileTask = variant.javaCompileProvider.get() + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } - task "jar${name}"(type: Jar, dependsOn: javaCompileTask) { - from javaCompileTask.destinationDir - } - } + // Add the block below if you're using Kotlin + kotlinOptions { + jvmTarget = "17" + } - artifacts { - archives androidSourcesJar - archives androidJavadocJar - } + buildFeatures { + viewBinding true + } - task installArchives(type: Upload) { - configuration = configurations.archives - repositories.mavenDeployer { - // Deploy to react-native-event-bridge/maven, ready to publish to npm - repository url: "file://${projectDir}/../android/maven" - configureReactNativePom pom - } - } } + +repositories { + mavenCentral() + google() +} + +def kotlin_version = getExtOrDefault("kotlinVersion") + +dependencies { + // For < 0.71, this will be from the local maven repo + // For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin + //noinspection GradleDynamicVersion + implementation "com.facebook.react:react-native:+" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" + + // mapbox dependencies + implementation "com.mapbox.navigation:android:2.19.0" + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + implementation 'androidx.cardview:cardview:1.0.0' +} + +if (isNewArchitectureEnabled()) { + react { + jsRootDir = file("../src/") + libraryName = "MapboxNavigationView" + codegenJavaPackageName = "com.homee.mapboxnavigation" + } +} \ No newline at end of file diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 00000000..03b0acc8 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +MapboxNavigation_kotlinVersion=1.6.0 +MapboxNavigation_compileSdkVersion=33 +MapboxNavigation_minSdkVersion=21 +MapboxNavigation_targetSdkVersion=33 \ No newline at end of file diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..ccebba77 Binary files /dev/null and b/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..46549df2 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +#Mon Feb 12 09:11:13 IST 2024 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/android/gradlew b/android/gradlew new file mode 100755 index 00000000..79a61d42 --- /dev/null +++ b/android/gradlew @@ -0,0 +1,244 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/android/gradlew.bat b/android/gradlew.bat new file mode 100644 index 00000000..6689b85b --- /dev/null +++ b/android/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/android/src/main/java/com/homee/mapboxnavigation/MapboxNavigationManager.kt b/android/src/main/java/com/homee/mapboxnavigation/MapboxNavigationManager.kt index 03823a5a..f88caeda 100644 --- a/android/src/main/java/com/homee/mapboxnavigation/MapboxNavigationManager.kt +++ b/android/src/main/java/com/homee/mapboxnavigation/MapboxNavigationManager.kt @@ -13,77 +13,110 @@ import com.mapbox.maps.TileStoreUsageMode import javax.annotation.Nonnull class MapboxNavigationManager(var mCallerContext: ReactApplicationContext) : SimpleViewManager() { - private var accessToken: String? = null - - init { - mCallerContext.runOnUiQueueThread { - try { - val app = mCallerContext.packageManager.getApplicationInfo(mCallerContext.packageName, PackageManager.GET_META_DATA) - val bundle = app.metaData - val accessToken = bundle.getString("MAPBOX_ACCESS_TOKEN") - this.accessToken = accessToken - ResourceOptionsManager.getDefault(mCallerContext, accessToken).update { - tileStoreUsageMode(TileStoreUsageMode.READ_ONLY) - } - } catch (e: PackageManager.NameNotFoundException) { - e.printStackTrace() - } + private var accessToken: String? = null + init { + mCallerContext.runOnUiQueueThread { + try { + val app = mCallerContext.packageManager.getApplicationInfo(mCallerContext.packageName, PackageManager.GET_META_DATA) + val bundle = app.metaData + val accessToken = bundle.getString("MAPBOX_ACCESS_TOKEN") + this.accessToken = accessToken + ResourceOptionsManager.getDefault(mCallerContext, accessToken).update { + tileStoreUsageMode(TileStoreUsageMode.READ_ONLY) } + } catch (e: PackageManager.NameNotFoundException) { + e.printStackTrace() + } } + } + override fun getName(): String = "MapboxNavigation" - override fun getName(): String { - return "MapboxNavigation" - } + public override fun createViewInstance(@Nonnull reactContext: ThemedReactContext): MapboxNavigationView { + return MapboxNavigationView(reactContext, this.accessToken) + } - public override fun createViewInstance(@Nonnull reactContext: ThemedReactContext): MapboxNavigationView { - return MapboxNavigationView(reactContext, this.accessToken) - } + override fun onDropViewInstance(view: MapboxNavigationView) { + view.onDropViewInstance() + super.onDropViewInstance(view) + } - override fun onDropViewInstance(view: MapboxNavigationView) { - view.onDropViewInstance() - super.onDropViewInstance(view) - } + override fun getExportedCustomDirectEventTypeConstants(): MutableMap>? { + return MapBuilder.of>( + "onLocationChange", MapBuilder.of("registrationName", "onLocationChange"), + "onError", MapBuilder.of("registrationName", "onError"), + "onCancelNavigation", MapBuilder.of("registrationName", "onCancelNavigation"), + "onArrive", MapBuilder.of("registrationName", "onArrive"), + "onRouteProgressChange", MapBuilder.of("registrationName", "onRouteProgressChange"), + ) + } - override fun getExportedCustomDirectEventTypeConstants(): MutableMap>? { - return MapBuilder.of>( - "onLocationChange", MapBuilder.of("registrationName", "onLocationChange"), - "onError", MapBuilder.of("registrationName", "onError"), - "onCancelNavigation", MapBuilder.of("registrationName", "onCancelNavigation"), - "onArrive", MapBuilder.of("registrationName", "onArrive"), - "onRouteProgressChange", MapBuilder.of("registrationName", "onRouteProgressChange"), - ) + @ReactProp(name = "origin") + fun setOrigin(view: MapboxNavigationView, sources: ReadableArray?) { + if (sources == null) { + view.setOrigin(null) + return } + view.setOrigin(Point.fromLngLat(sources.getDouble(0), sources.getDouble(1))) + } - @ReactProp(name = "origin") - fun setOrigin(view: MapboxNavigationView, sources: ReadableArray?) { - if (sources == null) { - view.setOrigin(null) - return - } - view.setOrigin(Point.fromLngLat(sources.getDouble(0), sources.getDouble(1))) + @ReactProp(name = "destination") + fun setDestination(view: MapboxNavigationView, sources: ReadableArray?) { + if (sources == null) { + view.setDestination(null) + return } + view.setDestination(Point.fromLngLat(sources.getDouble(0), sources.getDouble(1))) + } - @ReactProp(name = "destination") - fun setDestination(view: MapboxNavigationView, sources: ReadableArray?) { - if (sources == null) { - view.setDestination(null) - return - } - view.setDestination(Point.fromLngLat(sources.getDouble(0), sources.getDouble(1))) - } + @ReactProp(name = "shouldSimulateRoute") + fun setShouldSimulateRoute(view: MapboxNavigationView, shouldSimulateRoute: Boolean) { + view.setShouldSimulateRoute(shouldSimulateRoute) + } - @ReactProp(name = "shouldSimulateRoute") - fun setShouldSimulateRoute(view: MapboxNavigationView, shouldSimulateRoute: Boolean) { - view.setShouldSimulateRoute(shouldSimulateRoute) - } + @ReactProp(name = "showsEndOfRouteFeedback") + fun setShowsEndOfRouteFeedback(view: MapboxNavigationView, showsEndOfRouteFeedback: Boolean) { + view.setShowsEndOfRouteFeedback(showsEndOfRouteFeedback) + } - @ReactProp(name = "showsEndOfRouteFeedback") - fun setShowsEndOfRouteFeedback(view: MapboxNavigationView, showsEndOfRouteFeedback: Boolean) { - view.setShowsEndOfRouteFeedback(showsEndOfRouteFeedback) - } + @ReactProp(name = "mute") + fun setMute(view: MapboxNavigationView, mute: Boolean) { + view.setMute(mute) + } - @ReactProp(name = "mute") - fun setMute(view: MapboxNavigationView, mute: Boolean) { - view.setMute(mute) - } -} + @ReactProp(name = "waypoints") + fun setWaypoints(view: MapboxNavigationView, waypointsArray: ReadableArray?) { + waypointsArray?.let { + val waypoints = mutableListOf() + for (i in 0 until it.size()) { + val waypointArray = it.getArray(i) + if (waypointArray !== null && waypointArray.size() >= 2) { + val longitude = waypointArray.getDouble(0) + val latitude = waypointArray.getDouble(1) + waypoints.add(Point.fromLngLat(longitude, latitude)) + } + } + + view.setWaypoints(waypoints) + } + } + + @ReactProp(name = "vehicleMaxHeight") + fun setMaxHeight(view: MapboxNavigationView, height: Int?) { + if (height == null) { + view.setMaxHeight(1.6) + return + } + view.setMaxHeight(height?.toDouble()) + } + + @ReactProp(name = "vehicleMaxWidth") + fun setMaxWidth(view: MapboxNavigationView, width: Int?) { + if (width == null) { + view.setMaxWidth(1.9) + return + } + view.setMaxWidth(width?.toDouble()) + } + + +} \ No newline at end of file diff --git a/android/src/main/java/com/homee/mapboxnavigation/MapboxNavigationPackage.kt b/android/src/main/java/com/homee/mapboxnavigation/MapboxNavigationPackage.kt index 4f8c5503..5358ed75 100644 --- a/android/src/main/java/com/homee/mapboxnavigation/MapboxNavigationPackage.kt +++ b/android/src/main/java/com/homee/mapboxnavigation/MapboxNavigationPackage.kt @@ -4,16 +4,13 @@ import com.facebook.react.ReactPackage import com.facebook.react.bridge.NativeModule import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.uimanager.ViewManager -import java.util.* class MapboxNavigationPackage : ReactPackage { - override fun createNativeModules(reactContext: ReactApplicationContext): List { - return emptyList() - } + override fun createNativeModules(reactContext: ReactApplicationContext): List { + return emptyList() + } - override fun createViewManagers(reactContext: ReactApplicationContext): List> { - return Arrays.asList>( - MapboxNavigationManager(reactContext) - ) - } + override fun createViewManagers(reactContext: ReactApplicationContext): List> { + return listOf(MapboxNavigationManager(reactContext)) + } } \ No newline at end of file diff --git a/android/src/main/java/com/homee/mapboxnavigation/MapboxNavigationView.kt b/android/src/main/java/com/homee/mapboxnavigation/MapboxNavigationView.kt index a4d41818..0da01ae5 100644 --- a/android/src/main/java/com/homee/mapboxnavigation/MapboxNavigationView.kt +++ b/android/src/main/java/com/homee/mapboxnavigation/MapboxNavigationView.kt @@ -87,9 +87,12 @@ class MapboxNavigationView(private val context: ThemedReactContext, private val } private var origin: Point? = null + private var waypoints: List? = null private var destination: Point? = null private var shouldSimulateRoute = false private var showsEndOfRouteFeedback = false + private var maxHeight: Double? = null + private var maxWidth: Double? = null /** * Debug tool used to play, pause and seek route progress events that can be used to produce mocked location updates along the route. */ @@ -627,7 +630,13 @@ class MapboxNavigationView(private val context: ThemedReactContext, private val mapboxNavigation.registerVoiceInstructionsObserver(voiceInstructionsObserver) mapboxNavigation.registerRouteProgressObserver(replayProgressObserver) - this.origin?.let { this.destination?.let { it1 -> this.findRoute(it, it1) } } + // Create a list of coordinates that includes origin, destination, and waypoints + val coordinatesList = mutableListOf() + this.origin?.let { coordinatesList.add(it) } + this.waypoints?.let { coordinatesList.addAll(it) } + this.destination?.let { coordinatesList.add(it) } + + findRoute(coordinatesList) } override fun onDetachedFromWindow() { @@ -649,16 +658,22 @@ class MapboxNavigationView(private val context: ThemedReactContext, private val voiceInstructionsPlayer.shutdown() } - private fun findRoute(origin: Point, destination: Point) { + private fun findRoute(coordinates: List) { try { + val routeOptionsBuilder = RouteOptions.builder() + .applyDefaultNavigationOptions() + .applyLanguageAndVoiceUnitOptions(context) + .coordinatesList(coordinates) + .profile(DirectionsCriteria.PROFILE_DRIVING) + .steps(true) + + maxHeight?.let { routeOptionsBuilder.maxHeight(it) } + maxWidth?.let { routeOptionsBuilder.maxWidth(it) } + + val routeOptions = routeOptionsBuilder.build() + mapboxNavigation.requestRoutes( - RouteOptions.builder() - .applyDefaultNavigationOptions() - .applyLanguageAndVoiceUnitOptions(context) - .coordinatesList(listOf(origin, destination)) - .profile(DirectionsCriteria.PROFILE_DRIVING) - .steps(true) - .build(), + routeOptions, object : RouterCallback { override fun onRoutesReady( routes: List, @@ -749,6 +764,10 @@ class MapboxNavigationView(private val context: ThemedReactContext, private val this.origin = origin } + fun setWaypoints(waypoints: List) { + this.waypoints = waypoints + } + fun setDestination(destination: Point?) { this.destination = destination } @@ -764,4 +783,12 @@ class MapboxNavigationView(private val context: ThemedReactContext, private val fun setMute(mute: Boolean) { this.isVoiceInstructionsMuted = mute } -} + + fun setMaxHeight(maxHeight: Double?) { + this.maxHeight = maxHeight + } + + fun setMaxWidth(maxWidth: Double?) { + this.maxWidth = maxWidth + } +} \ No newline at end of file diff --git a/android/src/main/res/layout/navigation_view.xml b/android/src/main/res/layout/navigation_view.xml index a3d68a9e..d8629aaf 100644 --- a/android/src/main/res/layout/navigation_view.xml +++ b/android/src/main/res/layout/navigation_view.xml @@ -26,19 +26,20 @@ + android:layout_gravity="fill|left" + android:layout_marginStart="16dp" + android:layout_marginTop="8dp" /> + app:srcCompat="@android:drawable/ic_delete" + app:tint="@android:color/darker_gray" /> void; - onRouteProgressChange?: (event: OnRouteProgressChangeEvent) => void; - onError?: (event: OnErrorEvent) => void; - onCancelNavigation?: () => void; - onArrive?: () => void; - showsEndOfRouteFeedback?: boolean; - hideStatusView?: boolean; - mute?: boolean; + origin: Coordinate; + destination: Coordinate; + shouldSimulateRoute?: boolean; + onLocationChange?: (event: OnLocationChangeEvent) => void; + onRouteProgressChange?: (event: OnRouteProgressChangeEvent) => void; + onError?: (event: OnErrorEvent) => void; + onCancelNavigation?: () => void; + onArrive?: () => void; + showsEndOfRouteFeedback?: boolean; + hideStatusView?: boolean; + mute?: boolean; + waypoints?: Coordinate[]; + vehicleMaxHeight?: number; + vehicleMaxWidth?: number; } export {}; diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties index 7665b0fa..b93c46a5 100755 --- a/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.9-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/example/ios/BasicApp.xcodeproj/project.pbxproj b/example/ios/BasicApp.xcodeproj/project.pbxproj index 33137a91..f6d33fb2 100644 --- a/example/ios/BasicApp.xcodeproj/project.pbxproj +++ b/example/ios/BasicApp.xcodeproj/project.pbxproj @@ -564,7 +564,7 @@ COPY_PHASE_STRIP = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; - "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "arm64 "; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = ""; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -629,7 +629,7 @@ COPY_PHASE_STRIP = YES; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; - "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "arm64 "; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = ""; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 39778c91..109f6ac3 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -235,8 +235,8 @@ PODS: - React-jsinspector (0.66.4) - React-logger (0.66.4): - glog - - react-native-mapbox-navigation (1.1.0): - - MapboxNavigation (~> 2.1.0) + - react-native-mapbox-navigation (2.0.1): + - MapboxNavigation (~> 2.1.1) - React-Core - React-perflogger (0.66.4) - React-RCTActionSheet (0.66.4): @@ -451,7 +451,7 @@ SPEC CHECKSUMS: React-jsiexecutor: 94ce921e1d8ce7023366873ec371f3441383b396 React-jsinspector: d0374f7509d407d2264168b6d0fad0b54e300b85 React-logger: 933f80c97c633ee8965d609876848148e3fef438 - react-native-mapbox-navigation: 0966e03abd15664a2255a40f315c91e109a8a054 + react-native-mapbox-navigation: 04e8379f8a2d308e5a292bdbc3a79ac883e2d1d4 React-perflogger: 93075d8931c32cd1fce8a98c15d2d5ccc4d891bd React-RCTActionSheet: 7d3041e6761b4f3044a37079ddcb156575fb6d89 React-RCTAnimation: 743e88b55ac62511ae5c2e22803d4f503f2a3a13 @@ -470,4 +470,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: b825e0c0c2130ea0c4924baa443a786ab3686731 -COCOAPODS: 1.11.2 +COCOAPODS: 1.14.3 diff --git a/ios/MapboxNavigationManager.m b/ios/MapboxNavigationManager.m index 7e4c8f1f..b18c5c7c 100644 --- a/ios/MapboxNavigationManager.m +++ b/ios/MapboxNavigationManager.m @@ -13,5 +13,8 @@ @interface RCT_EXTERN_MODULE(MapboxNavigationManager, RCTViewManager) RCT_EXPORT_VIEW_PROPERTY(showsEndOfRouteFeedback, BOOL) RCT_EXPORT_VIEW_PROPERTY(hideStatusView, BOOL) RCT_EXPORT_VIEW_PROPERTY(mute, BOOL) +RCT_EXPORT_VIEW_PROPERTY(waypoints, NSArray) +RCT_EXPORT_VIEW_PROPERTY(vehicleMaxHeight, NSNumber) +RCT_EXPORT_VIEW_PROPERTY(vehicleMaxWidth, NSNumber) @end diff --git a/ios/MapboxNavigationView.swift b/ios/MapboxNavigationView.swift index aa361521..7ea058f9 100644 --- a/ios/MapboxNavigationView.swift +++ b/ios/MapboxNavigationView.swift @@ -24,6 +24,10 @@ class MapboxNavigationView: UIView, NavigationViewControllerDelegate { @objc var origin: NSArray = [] { didSet { setNeedsLayout() } } + + @objc var waypoints: NSArray = [] { + didSet { setNeedsLayout() } + } @objc var destination: NSArray = [] { didSet { setNeedsLayout() } @@ -39,6 +43,8 @@ class MapboxNavigationView: UIView, NavigationViewControllerDelegate { @objc var onError: RCTDirectEventBlock? @objc var onCancelNavigation: RCTDirectEventBlock? @objc var onArrive: RCTDirectEventBlock? + @objc var vehicleMaxHeight: NSNumber? + @objc var vehicleMaxWidth: NSNumber? override init(frame: CGRect) { self.embedded = false @@ -74,9 +80,30 @@ class MapboxNavigationView: UIView, NavigationViewControllerDelegate { let originWaypoint = Waypoint(coordinate: CLLocationCoordinate2D(latitude: origin[1] as! CLLocationDegrees, longitude: origin[0] as! CLLocationDegrees)) let destinationWaypoint = Waypoint(coordinate: CLLocationCoordinate2D(latitude: destination[1] as! CLLocationDegrees, longitude: destination[0] as! CLLocationDegrees)) + var waypointsArray = [originWaypoint] + + // Adding intermediate waypoints if any + for waypointArray in waypoints { + if let waypointCoordinates = waypointArray as? NSArray, waypointCoordinates.count == 2, + let lat = waypointCoordinates[1] as? CLLocationDegrees, let lon = waypointCoordinates[0] as? CLLocationDegrees { + let waypoint = Waypoint(coordinate: CLLocationCoordinate2D(latitude: lat, longitude: lon)) + waypointsArray.append(waypoint) + } + } + + waypointsArray.append(destinationWaypoint) + // let options = NavigationRouteOptions(waypoints: [originWaypoint, destinationWaypoint]) let options = NavigationRouteOptions(waypoints: [originWaypoint, destinationWaypoint], profileIdentifier: .automobileAvoidingTraffic) + if let vehicleMaxHeight = vehicleMaxHeight?.doubleValue { + options.includesMaxHeightOnMostRestrictiveBridge = true + options.maxHeight = vehicleMaxHeight + } + if let vehicleMaxWidth = vehicleMaxWidth?.doubleValue { + options.maxWidth = vehicleMaxWidth + } + Directions.shared.calculate(options) { [weak self] (_, result) in guard let strongSelf = self, let parentVC = strongSelf.parentViewController else { return diff --git a/react-native-mapbox-navigation.podspec b/react-native-mapbox-navigation.podspec index 387ebc41..4d42b3b5 100644 --- a/react-native-mapbox-navigation.podspec +++ b/react-native-mapbox-navigation.podspec @@ -39,13 +39,13 @@ Pod::Spec.new do |s| s.homepage = "https://github.com/homeeondemand/react-native-mapbox-navigation" s.license = { :type => "MIT", :file => "LICENSE" } s.authors = { "HOMEE" => "support@homee.com" } - s.platforms = { :ios => "11.0" } + s.platforms = { :ios => "12.4" } s.source = { :git => "https://github.com/homeeondemand/react-native-mapbox-navigation.git", :tag => "#{s.version}" } s.source_files = "ios/**/*.{h,m,swift}" s.requires_arc = true s.dependency "React-Core" - s.dependency "MapboxNavigation", "~> 2.1.1" + s.dependency "MapboxNavigation", "~> 2.17.0" end diff --git a/src/typings.ts b/src/typings.ts index 91c5cd0b..19ced945 100644 --- a/src/typings.ts +++ b/src/typings.ts @@ -37,4 +37,7 @@ export interface IMapboxNavigationProps { showsEndOfRouteFeedback?: boolean; hideStatusView?: boolean; mute?: boolean; + waypoints?: Coordinate[]; + vehicleMaxHeight?: number; + vehicleMaxWidth?: number; }