iT邦幫忙

2023 iThome 鐵人賽

DAY 23
0

本篇要來介紹Expo地理位置追蹤套件 - Expo Location
講解在React Native Expo專案怎麼做到

  • 一次性取得使用者位置
  • 背景追蹤使用者位置

開發前注意事項

取得位置是非常隱私的項目
在下載其他APP時,不彷查看APP是否使用位置,使用了要做甚麼
是使用一次,還是背景永遠使用

https://ithelp.ithome.com.tw/upload/images/20230927/20130821LVRwNp4EEF.png

否則APP一直莫名其妙在追蹤你的位置
位置資訊可能已經傳到後台做非法利用了😮

APP上架審查嚴格

也因為位置是非常隱私,甚至防有心人士追蹤位置的功能
Play 商店 & App Store 在上架審查時
對於位置追蹤審查是非常嚴格的(往往要送上審查說明、Demo影片...等)

開發位置追蹤程度

先評估開發前要做到哪一項需求

  • 取得一次位置
  • 全程背景追蹤位置

哪種類型的APP只需一次性位置

  • 公司打卡APP
  • 天氣
  • Youbike 找單車
  • Uber 叫車

哪種類型的APP需要背景位置追蹤

  • 朋友 & 家人追蹤 (抓猴神器)
  • Apple Watch
  • 消防、毒災、醫務相關
  • 交通導航相關、Gogoro電動車
  • 部分社群平台(Instagram興趣探索功能)

Expo Location 地理位置套件

介紹

官方介紹 & Usage:https://docs.expo.dev/versions/latest/sdk/location/
Expo Location用於地理資訊位置追蹤
可以獲得當前手機位置座標、檢查APP位置權限
該套件還有座標轉地址、電子圍籬、指南針...等地理資訊功能
本篇只介紹GPS位置紀錄部分

安裝

npx expo install expo-location
使用版本:16.1.0

一次性取得使用者位置

位置權限設定

只要牽扯隱私權相關,就一定得設定這些隱私權
讓使用者知道你的APP要取得他的位置
否則會觸犯個資法😮

手機定位資訊係屬個人資料保護法第2 條第1 款規定之個人資料,為隱私權保護之 一環

修改app.json
android & ios標籤分別加入權限相關功能

  "ios": {
    "supportsTablet": true,
    "infoPlist": {      
      "NSLocationUsageDescription": "啟用定位服務 才能使用定位功能",
      "NSLocationWhenInUseUsageDescription": "啟用定位服務 才能使用定位功能",
    }
  },
  "android": {
    "adaptiveIcon": {
      "foregroundImage": "./assets/adaptive-icon.png",
      "backgroundColor": "#ffffff"
    },
    "package": "com.xxxx.expoapp",
    "permissions":["ACCESS_COARSE_LOCATION","ACCESS_FINE_LOCATION"]
  },

Android權限講解:
ACCESS_COARSE_LOCATION 允許應用程式存取大概位置。
ACCESS_FINE_LOCATION 允許應用程式存取精確位置。

IOS權限講解:
NSLocationUsageDescription 告訴用戶應用程式第一次啟動並請求位置權限時
系統將向用戶顯示此描述
NSLocationWhenInUseUsageDescription 告訴用戶應用程式為何僅在使用時需要位置權限時
向用戶解釋原因

使用方法

引入expo-location
import * as Location from 'expo-location';

檢查前景GPS權限

async function VaildGPSPremission() {
    let { status } = await Location.requestForegroundPermissionsAsync();
    if (status !== "granted") {
      Alert.alert("尚未打開手機GPS定位功能");
      return false;
    } else {
      return true;
    }
  }

取得一次位置

async function GetLocation() {
    try {
      let location = await Location.getCurrentPositionAsync({accuracy: Location.Accuracy.Balanced});
      return location;
    } catch (e) {
      console.log(e);
    }
  }

accuracy可以調整位置精準度
取得速度會因使用者的GPS訊號、網路速度而改變
要注意的是,越精準速度越慢,反之越快
建議使用BalancedHigh
其他選項不是偏差太多,就是太慢

  • Accuracy.Lowest 三公里以內
  • Accuracy.Low 一公里以內
  • Accuracy.Balanced 一百米以內
  • Accuracy.High 十米以內
  • Accuracy.Highest 最高精準度
  • Accuracy.BestForNavigation 傳感器準度支援(運動手錶、行車紀錄器)

return location Json格式參考

{
  "coords": {
    "altitude": 21.195085525512695,
    "altitudeAccuracy": 2.2917959690093994,
    "latitude": 25.02579835865695,
    "accuracy": 35,
    "longitude": 121.50828483818138,
    "heading": -1,
    "speed": -13,
    "timestamp": 1658717013053.115
  }
}

介紹常用的回傳屬性應用

  • latitude 緯度
  • longitude 經度
  • heading 方向(0~360)
  • speed 行進速度
  • timestamp 位置取得時間

背景追蹤使用者位置

背景位置追蹤功能相對一次性取得位置
困難度會大幅提升
文章篇幅較長還請見諒🥺

環境準備

Expo專案對於「背景執行功能」有一項限制

TaskManager works out of the box in the Expo Go app on Android, however, on iOS, you'll need to use a development build.

也就是執行APP時
只有在Using development build 預覽模式才能使用
Using Expo Go 無法支援背景執行功能

官方只提到IOS不支援Expo Go背景執行
這邊建議Android也使用預覽模式,會比較貼近真實手機運行狀況

  • Windows使用者
    建議使用Android Studio模擬器(AVD Manager)
    GenyMotion對於模擬GPS功能較差,故不使用
  • MAC使用者
    使用XCode中的模擬器(Simulator-iphone)即可,要記得開啟位置權限
    MAC也要額外安裝CocoaPods原生套件管理
    也可使用Homebrew套件安裝

尚未安裝Android Studio的話記得先裝:Android Studio官方安裝連結
AVD Manager建置參考Android鐵人:Android Studio - 安卓手機模擬器AVD Manager

安裝expo-task-manager

expo-task-manager是一種可以讓你的APP在背景執行工作的套件
即使你螢幕關掉、滑掉,APP還會繼續工作
若想開發定位以外的定時背景服務,需使用Expo BackgroundFetch

安裝指令:
npx expo install expo-task-manager
使用版本:11.3.0

app.json加入背景追蹤權限設定

參考上方app.json設定方法,額外新增以下權限

  • Android多了一項background權限:
    "permissions":["ACCESS_COARSE_LOCATION","ACCESS_FINE_LOCATION","ACCESS_BACKGROUND_LOCATION"]
  • IOS多了UIBackgroundModes權限:
    "UIBackgroundModes": ["location", "fetch"]
  • IOS描述(infoplist)增加總是詢問權限:
"NSLocationAlwaysAndWhenInUseUsageDescription": "啟用定位服務 才能使用背景定位功能",
"NSLocationAlwaysUsageDescription": "啟用定位服務 才能使用背景定位功能"

Android背景權限講解

  1. ACCESS_BACKGROUND_LOCATION 應用程式獲得前景位置資訊存取權時,該應用程式也會自動獲得背景位置資訊存取權

IOS背景權限講解:

  1. NSLocationAlwaysAndWhenInUseUsageDescription 在應用程式同時需要「永遠」(Always)和「當使用時」(When In Use)位置權限時向用戶解釋原因
  2. NSLocationAlwaysUsageDescription 應用程式需要在背景中始終追蹤位置時向用戶解釋原因,這個選項只有「永遠」和「使用一次」。

使用方法

引入位置元件、APP背景工作管理器

import * as TaskManager from "expo-task-manager";
import * as Location from 'expo-location';

定義背景工作名稱

const LOCATION_TRACKING = "location-tracking";

檢查背景GPS權限

async function VaildGPSPremission() {
    let { status } = await Location.requestBackgroundPermissionsAsync();
    if (status !== "granted") {
      Alert.alert("手機GPS背景定位需設定成使用期間或是永遠");
      return false;
    } else {
      return true;
    }
  }

背景追蹤核心function

程式碼解釋:
先向LOCATION_TRACKING工作註冊定期追蹤功能
確認註冊完成後hasStarted
在使用TaskManager.defineTask定義為背景工作

async function StartLocationTracking() {
  await Location.startLocationUpdatesAsync(LOCATION_TRACKING, {
    accuracy: Location.Accuracy.Balanced,
    timeInterval: 5000,
    deferredUpdatesInterval: 10000,
    deferredUpdatesDistance: 0,
    distanceInterval: 0,
    foregroundService: {
      notificationTitle: "GPS",
      notificationBody: "body",
      notificationColor: "#0000FF",
    },
  });
  const hasStarted = await Location.hasStartedLocationUpdatesAsync(
    LOCATION_TRACKING
  );
  if (hasStarted) {
    TaskManager.defineTask(LOCATION_TRACKING, async ({ data, error }) => {
      if (error) {
        console.log("LOCATION_TRACKING task ERROR:", error);
        return;
      }
      if (data) {
        const { locations } = data;
        let lat = locations[0].coords.latitude;
        let long = locations[0].coords.longitude;
        console.log(`${new Date(Date.now()).toLocaleString()}: ${lat},${long}`);
      } else {
        console.log("no gps data");
      }
    });
  }
}

LocationTaskOptions 定期位置追蹤設定講解

  • accuracy 精準度,可參考上方一次性定位設定
  • timeInterval 位置更新最短時間間隔(毫秒)
  • distanceInterval 移動超過指定距離時,才觸發位置更新(米)
  • deferredUpdatesInterval 延遲位置更新時間間隔(毫秒)
  • deferredUpdatesDistance 延遲移動超過指定距離時,才觸發位置更新(米)
  • foregroundService 在APP通知選單顯示正在被背景追蹤

deferred 指的是背景執行時會發生延遲的狀況
distance 會回傳比較少的位置,移動距離若不遠則不會回傳多餘資訊

目前使用console.log追蹤位置data
可自行調整是否要回傳伺服器
或使用useContext傳遞位置資訊給使用者看

停止背景追蹤function

function StopLocationTracking() {
  TaskManager.isTaskRegisteredAsync(LOCATION_TRACKING).then((tracking) => {
    if (tracking) {
      Location.stopLocationUpdatesAsync(LOCATION_TRACKING);
    }
  });
}

完整程式碼可參考外國大神針對背景追蹤撰寫的文章:
https://arnav25.medium.com/background-location-tracking-in-react-native-d03bb7652602

使用模擬器/真實設備測試

npx expo start 主要用於開發過程中的本地預覽和除錯,而 npx expo run:android 用於在 Android 設備或模擬器上運行你的應用程序以進行更全面的測試。這兩個命令通常在不同的階段和用途中使用

啟動指令:npx expo run:android --device
該啟動指令會直接使用development build模式執行APP
--device 參數可以自行選擇設備

該指令像是直接在實體機器/模擬器安裝APP,而不是使用Expo Go執行
真實設備插入Usb進電腦就能使用

啟動背景追蹤前
Android模擬器需先關閉「未使用APP暫停活動」
Pause app activity if unused
調整重開APP後在進行背景追蹤

https://ithelp.ithome.com.tw/upload/images/20230927/20130821nRdOEmhoua.png

背景追蹤效果如下

Google Pixel XL:
Android版本:13

img

Iphone 14 Pro Max:
IOS版本:16

img

可以看到關閉螢幕、關閉APP時
仍在記錄使用者的位置


結語:
位置追蹤功能大概是做專案以來
花最長時間在學習、開發、測試的環節

也從中學習到自己所安裝的APP
是怎麼追蹤位置資訊的

Expo套件介紹系列,到這邊也告一段落了
下一篇要來介紹
Mockapi 後端資料測試前後端串接
讓前端APP能與API溝通並回傳、驗證

隨著鐵人賽文章接近尾聲
下一篇也是最後一篇開發環節了😥。


上一篇
Day 22 - Expo 語音功能、觸覺回饋、震動功能應用
下一篇
Day 24 - 使用 Fetch 和 MockAPI 模擬真實資料 feat.環境變數
系列文
單人開發者之路:React Native 與 Expo 帶你從開發到上架30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言