From 320003e1dbf6ac03798b9f6842eaa4f1bf77c4eb Mon Sep 17 00:00:00 2001 From: Rodolphe Fauquez Date: Mon, 29 Jan 2018 02:25:37 +0000 Subject: [PATCH] Merged in CLT-711_geolocalisation_android (pull request #59) CLT-711 geolocalisation android * - The problem was from High_Accuracy in Android. Removed the 3rd parameter in getCurrentPosition. Now working, even if the user location type is high_accuracy in his android parameters. - Also added alert messages to the user: Because if he allow the permission, but his location stay disabled, the application provide no feedback to the user. * - add little library who can handle (with playservices) the high_precision issue for Android https://github.com/facebook/react-native/issues/7495 - added some prompt message to the user to let him know the problem in case of failure - added requestPermissionLocation (e.g if the permission was removed after install) - Removed some not used imports in ChatSaga * removed Alerts * Documented error 5 and added github link in comment Approved-by: Aaron Lee --- App/Sagas/ChatSagas.js | 49 ++++++++---- App/Services/Geolocation.js | 77 +++++++++++++++---- android/app/build.gradle | 5 ++ .../java/com/clintal/MainApplication.java | 4 +- android/settings.gradle | 2 + package-lock.json | 5 ++ package.json | 1 + 7 files changed, 110 insertions(+), 33 deletions(-) diff --git a/App/Sagas/ChatSagas.js b/App/Sagas/ChatSagas.js index 6b79a82fc..71c132753 100644 --- a/App/Sagas/ChatSagas.js +++ b/App/Sagas/ChatSagas.js @@ -1,15 +1,18 @@ -import { put, take, call, select } from 'redux-saga/effects' +import { + put, + call, + select +} from 'redux-saga/effects' import ChatActions from '../Redux/ChatRedux' -import { NavigationActions } from 'react-navigation' -import {PlanType} from "../Models/PlanType" -import Validator from "validator" -import isSameDay from 'date-fns/is_same_day' import {ClintalMessage} from '../Models/ClintalMessage' -import {MessageCell} from '../Models/MessageCell' -import { Question, AnswerType } from '../Models/Question' -import { ChatUiType } from '../Models/ChatUiType'; -import RegistrationActions from "../Redux/RegisterRedux"; -import Geo from "../Services/Geolocation"; +import { + Question, + AnswerType +} from '../Models/Question' +import { ChatUiType } from '../Models/ChatUiType' +import RegistrationActions from '../Redux/RegisterRedux' +import Geo from '../Services/Geolocation' +import { PermissionsAndroid } from 'react-native' const pageSize = 20 @@ -180,6 +183,16 @@ export function * getBotQuestion (api, action) { } } +const requestLocationPermission = () => { + try { + PermissionsAndroid.request( + PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION, + ) + } catch (err) { + console.warn(err) + } +} + export function * postBotReplyFlow (api, action) { const {questionId, choice} = action @@ -203,15 +216,21 @@ export function * postBotReplyFlow (api, action) { // 現在地周辺 auto-detect current location try { const {latitude, longitude} = yield Geo.getCurrentPosition() - } catch(err) { + } catch (err) { + let errorMessage = '' + if (err.code === 1) { // PositionError.PERMISSION_DENIED - yield put(ChatActions.sendBotAnswerFailure("GPSの取得が許可されていません。設定をご確認ください。")) + errorMessage = "GPSの取得が許可されていません。設定をご確認ください。" + requestLocationPermission() + yield put(ChatActions.sendBotAnswerFailure(errorMessage)) } else if (err.code === 2) { // PositionError.POSITION_UNAVAILABLE - yield put(ChatActions.sendBotAnswerFailure("GPSの取得に失敗しました。設定をご確認ください。")) + errorMessage = "GPSの取得に失敗しました。設定をご確認ください。" + yield put(ChatActions.sendBotAnswerFailure(errorMessage)) } else { // PositionError.TIMEOUT - yield put(ChatActions.sendBotAnswerFailure("GPSの取得にタイムアウトしました。設定をご確認ください。")) + errorMessage = "GPSの取得にタイムアウトしました。設定をご確認ください。" + yield put(ChatActions.sendBotAnswerFailure(errorMessage)) } - return; + return } } response = yield call(api.postBotAnswerLocation, questionId, choice.id, latitude, longitude) diff --git a/App/Services/Geolocation.js b/App/Services/Geolocation.js index 7bd77d1a4..e2b35d54a 100644 --- a/App/Services/Geolocation.js +++ b/App/Services/Geolocation.js @@ -1,21 +1,64 @@ -const getCurrentPosition = () => { +import {Platform} from 'react-native' +import Geolocation from 'react-native-geolocation-service' + +let secondTryAgainGetPosition = false + +const getCurrentPosition = (enableHighAccuracy = true) => { return new Promise((resolve, reject) => { - navigator.geolocation.getCurrentPosition( - (position) => { - latitude = position.coords.latitude; - longitude = position.coords.longitude; - resolve({latitude, longitude}); - }, - (error) => { - reject(error) - }, - { - enableHighAccuracy: true, - timeout: 20000, - maximumAge: 1000 - } - ); - }); + /* The default navigator.geolocation.getCurrentPosition have some issues (TIMEOUT) with enableHighAccuracy: true in Android, + and removing the 3rd parameter or setting enableHighAccuracy to false do not resolve the problem, so + this custom library can handle it: + The google system will show a modal and give the possibility to activate the location service directly from the modal + so we don't have to ask to the user to do it manually + See more: https://github.com/Agontuk/react-native-geolocation-service */ + if (Platform.OS === 'android') { + Geolocation.getCurrentPosition( + (position) => { + latitude = position.coords.latitude; + longitude = position.coords.longitude; + resolve({latitude, longitude}); + }, + (error) => { + // See docs: 5 === SETTINGS_NOT_SATISFIED + // "Location service is not enabled or location mode is not appropriate for the current request" + if (error.code === 5) { + reject(error) + } else { + if (!secondTryAgainGetPosition) { + reject(error) + secondTryAgainGetPosition = true + getCurrentPosition(false) + } else { + secondTryAgainGetPosition = false + reject(error) + } + } + }, + { + enableHighAccuracy: enableHighAccuracy, + timeout: 20000, + maximumAge: 1000 + } + ) + } else { + //default system for ios + navigator.geolocation.getCurrentPosition( + (position) => { + latitude = position.coords.latitude; + longitude = position.coords.longitude; + resolve({latitude, longitude}); + }, + (error) => { + reject(error) + }, + { + enableHighAccuracy: true, + timeout: 20000, + maximumAge: 1000 + } + ) + } + }) } export default { diff --git a/android/app/build.gradle b/android/app/build.gradle index c28a26b4b..b9d4e7b9f 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -179,6 +179,11 @@ dependencies { compile 'com.google.android.gms:play-services-base:11.4.2' compile 'com.google.firebase:firebase-core:11.4.2' compile 'com.google.firebase:firebase-messaging:11.4.2' + + compile(project(':react-native-geolocation-service')) { + exclude group: 'com.google.android.gms', module: 'play-services-location' + } + compile 'com.google.android.gms:play-services-location:11.4.2' } // Run this once to be able to run the application with BUCK diff --git a/android/app/src/main/java/com/clintal/MainApplication.java b/android/app/src/main/java/com/clintal/MainApplication.java index 5d0adfea1..aa3f3208d 100644 --- a/android/app/src/main/java/com/clintal/MainApplication.java +++ b/android/app/src/main/java/com/clintal/MainApplication.java @@ -12,6 +12,7 @@ import com.facebook.react.ReactPackage; import com.facebook.react.shell.MainReactPackage; import com.facebook.soloader.SoLoader; +import com.agontuk.RNFusedLocation.RNFusedLocationPackage; import java.util.Arrays; import java.util.List; @@ -33,7 +34,8 @@ protected List getPackages() { new MainReactPackage(), new RNFirebasePackage(), new RNFirebaseMessagingPackage(), - new VectorIconsPackage() + new VectorIconsPackage(), + new RNFusedLocationPackage() ); } }; diff --git a/android/settings.gradle b/android/settings.gradle index 13aeead08..1d259d981 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -3,5 +3,7 @@ include ':react-native-firebase' project(':react-native-firebase').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-firebase/android') include ':react-native-vector-icons' project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android') +include ':react-native-geolocation-service' +project(':react-native-geolocation-service').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-geolocation-service/android') include ':app' diff --git a/package-lock.json b/package-lock.json index 130b7b41b..27394ca43 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11550,6 +11550,11 @@ "prop-types": "15.6.0" } }, + "react-native-geolocation-service": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/react-native-geolocation-service/-/react-native-geolocation-service-1.0.0.tgz", + "integrity": "sha512-CT5whUibOmZ36QvaKG+MYRtXHpz2ge11vVYX+SLxNQe4wxAsjpPQYR5UugK2yDwW9XsWbh9mktNcQblNGzaYtg==" + }, "react-native-gifted-chat": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/react-native-gifted-chat/-/react-native-gifted-chat-0.3.0.tgz", diff --git a/package.json b/package.json index 87051528e..821573e01 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "react-native-datepicker": "^1.6.0", "react-native-drawer": "^2.5.0", "react-native-firebase": "^3.1.1", + "react-native-geolocation-service": "^1.0.0", "react-native-gifted-chat": "^0.3.0", "react-native-hyperlink": "^0.0.11", "react-native-simple-radio-button": "^2.7.0",