« ^ »

macOSで現在の位置情報を取得する

所要時間: 約 2分

税務調査などが入った時に、「いつ」「どこで」「なにを」していたのかを回答できるように準備を進めたい。「いつ」「なにを」はタスク管理にOrg-modeを使用しているため、記録が残っていく。ただし「どこで」という情報は、今は残していない。スマホの機能ので記録できそうではあるが、スマホがあまり好きではない事と、大体電源が落ちている事が多いため役に立たない。そこでローカルのコマンドでも位置情報を取得する事にした。これはいくつかの方法があると思う。どこかのWeb APIを使用する方法、ブラウザのGeolocation APIを使用する方法なども考えたが、IPアドレスベースのAPIは精度があまり良くなく、ブラウザのGeolocation APIはヘッドレスモードのChromeを起動し、Chrome Dev Tool API経由で使う方法も考えたが、普通に大変そうだった。使用しているOSはmacOSであるため CoreLocation を使い、macOSが提供している機能を利用する方法が良さそうだ。そこで今回はSwiftで現在位置の緯度と経度を取得するプログラムを実装する。

import CoreLocation

class Foo: NSObject, CLLocationManagerDelegate {
    let locationManager = CLLocationManager()

    override init() {
        super.init()
        locationManager.delegate = self
        locationManager.requestWhenInUseAuthorization()
    }

    func requestLocationOnce() {
        locationManager.requestLocation()
    }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        guard let location = locations.last else { return }

        // 位置情報の取得成功
        print("Latitude: \(location.coordinate.latitude)")
        print("Longitude: \(location.coordinate.longitude)")

        exit(0)
        // 位置情報の取得が完了したので、RunLoopを停止する
        // DispatchQueue.main.async {
        //     CFRunLoopStop(CFRunLoopGetCurrent())
        // }
    }

    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        // 位置情報の取得失敗
        print("Error getting location: \(error.localizedDescription)")

        // 位置情報の取得が失敗したので、RunLoopを停止する
        DispatchQueue.main.async {
            CFRunLoopStop(CFRunLoopGetCurrent())
        }
    }
}

let foo = Foo()

foo.requestLocationOnce()

// RunLoopを開始し、イベントの待機と処理を行う
RunLoop.current.run()

実行する。

swift main.swift
Latitude: 12.123456789012345
Longitude: 123.1234567890123

緯度と経度を取得し標準出力に出力した後プログラム自体が終了する。もし実行できなかったら、macOSのセキュリティとプライバシーの設定の位置情報で許可が与えられているかを確認すると良い。

ここまで出来れば後はEmacsで出力を加工できそうだ。またこのコードの大半は、ChatGPTに書いてもらった。もう自分で実装しない方が良いかもなと思えるようになってきた。

この出力結果を、カレントバッファに書き込むEmacs Lispを書く事にする。とりあえず、バイナリとしてコンパイルする。

swiftc main.swift -o symdon-current-location

このバイナリをEmacs Lispの shell-command から呼び出せばよい。

(defun symdon-current-location ()
   (interactive)
   (shell-command "./symdon-current-location" t))

バイナリとして生成したり、そのファイルを移動すると、再度macOSのセキュリティとプライバシーの設定の位置情報で許可を与える必要がある。