Tauri 2.0でAndroidの位置情報取得機能を使ってみた

はじめに

Rustでデスクトップアプリを作るためのフレームワークであるTauri 2.0が正式リリースされました(https://v2.tauri.app/blog/tauri-20/)。

目新しい機能として次のようなものがあります。

今回、この2つの機能に触ってみたいと思います。 具体的には「現在の位置情報を取得して表示するAndroidアプリ」です。

では早速作り始めましょう。

必要なもののインストール

必要なものは次の通りです。

詳しくはこちらを読んでください。

プロジェクトの作成

お好きなパッケージ管理システムを使ってお好きなフレームワークと言語を使ってプロジェクトを構築してください。

今回自分はnpm + React + TypeScriptで作りました。

npm create tauri-app@latest
cd tauri-gps
npm install

このままビルドするとスマホからアクセスできない旨のエラーが出るので、src-tauri/tauri.conf.jsonbuild.beforeDevCommandの項目に--host引数を渡すように修正し、このようにします。:"npm run dev -- --host"

こちら(https://v2.tauri.app/start/prerequisites/#android)で挙げられている環境変数の設定ができたらAndroid用のバイナリのビルドを行います。

npm run tauri android init
npm run tauri android dev

これでアプリが立ち上がるはずです。

プラグインの追加

位置情報を取得するためのプラグインを追加します。

Tauriのプラグインで公式の物はhttps://github.com/tauri-apps/plugins-workspace/tree/v2/pluginsにあります。グッとにらむとどうやらgeolocationというやつがあるようです。これを探していくとcratesやdoc.rsなどのサイトが見つかります。

これらのドキュメントを元にプラグインを追加します。

npm add @tauri-apps/plugin-geolocation
cd src-tauri
cargo add tauri-plugin-geolocation

次にRustのファイルを変更します。src-tauri/src/lib.rsに次の一行を加えます。

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        .plugin(tauri_plugin_shell::init())
+        .plugin(tauri_plugin_geolocation::init())
        .invoke_handler(tauri::generate_handler![])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

これでプラグインが有効化されます。

位置情報を取得する機能を実装する

フロントエンド側で位置情報を取得する機能を実装します。 ここでは簡単に、ボタンを押すと位置情報を取得して緯度経度を丸めて表示するコードを書きます。

import { useState } from "react";
+import {
+  checkPermissions,
+  requestPermissions,
+  getCurrentPosition,
+  Position
+} from '@tauri-apps/plugin-geolocation'
import "./App.css";

function App() {

+  const [phonePos, setPhonePos] = useState<Position | null>(null);

+ async function getPos() {
+   let permissions = await checkPermissions()
+   if (
+     permissions.location === 'prompt' ||
+     permissions.location === 'prompt-with-rationale'
+   ) {
+     permissions = await requestPermissions(['location'])
+   }
+   
+   if (permissions.location === 'granted') {
+     const pos = await getCurrentPosition()
+     setPhonePos(pos);
+   }
+ }

  return (
    <div className="container">

+      <button onClick={getPos}>位置情報を取得</button>
+      <p>{phonePos ? <>({Math.round(phonePos.coords.latitude)}, {Math.round(phonePos.coords.longitude)})</>: null}</p>

    </div>
  );
}

export default App;

簡単に解説を書くと、

  1. checkPermissions()関数で現在の位置情報に関する権限を取得する
  2. 位置情報取得の権限が許可されていなかった場合はrequestPermissions(['location'])でユーザーに権限をリクエストする
  3. 権限がある場合はgetCurrentPosition()で位置情報を取得し、値を更新する
  4. 位置情報を表示する

となります。

位置情報の値はPosition型で表されます。この型の定義はdoc.rsに書いてあるものを自動変換しているようです。:https://docs.rs/tauri-plugin-geolocation/2.0.0/tauri_plugin_geolocation/struct.Position.html

権限の許可

これで表示されている「位置情報を取得する」ボタンを押してみると現在位置の緯度経度が表示される、かと思いきや表示されません。 それどころかターミナルには「権限が許可されていないよ」と出てきます。

この原因は2.0になって強化された権限回りにあります。1.0ではI/Oなどの操作ごとにallowlistで権限の許可を行っていましたが、2.0からはプラグインの各機能ごとに許可の有無を制御できるようになりました(https://v2.tauri.app/learn/security/using-plugin-permissions/)。

権限の許可はsrc-tauri/capabilities/default.jsonファイルで行います。 "permissions"プロパティに、このプラグインで追加された権限を追加します。 今回watchPositionという関数を使っていないので、この権限は許可していません。

{
  "$schema": "../gen/schemas/desktop-schema.json",
  "identifier": "default",
  "description": "Capability for the main window",
  "windows": ["main"],
  "permissions": [
    "core:default",
    "shell:allow-open",
+    "geolocation:allow-check-permissions",
+    "geolocation:allow-clear-permissions",
+    "geolocation:allow-get-current-position",
+    "geolocation:allow-request-permissions",
+    "geolocation:deny-watch-position",
+    "geolocation:deny-clear-watch"
  ]
}

動作結果

これで動くようになりました。位置情報を丸める前の結果が驚くほど正確でびっくりしました。凄いですね。

権限の許可を要求する画面

位置情報取得結果

まとめ

モバイルアプリも作れるようになったのは嬉しいですね。

これらのコードはGitHubで公開しています(https://github.com/puripuri2100/tauri-gps)。