jxaを使ってXcodeのSimulate Locationをキー入力で書き換えるアプリを作った

[以前作ったアプリ](https://qiita.com/kitanote/items/647d8949b740cc3ec2b3)のデバッグの際にSimulate Locationにはお世話になったのですが、毎回行きたい場所のgpxファイルを追加する必要があり、かなり面倒くさかったです。以下の記事で紹介されているAppleScriptは改良する気が起きなかったのでその時は手動でぽちぽちしてました。

[iPhoneの実機で位置情報をシミュレーションする方法 - Qiita](https://qiita.com/narikei/items/c20d95532130e8fcdeb7)

## JavaScriptで書ける

[知らないうちにMacがシステム標準でJavaScriptで操作できるようになってた (JXA) - Qiita](https://qiita.com/zakuroishikuro/items/1b02378bf9e940602d87)

ずっとMac使ってたのですが、知りませんでした:scream_cat:
JavaScirptで書けるということでちょっと触ってみたところ、結構おもしろい。

## 作ったもの

![output.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510204/247708e0-0678-8941-f65c-b32bab11d205.gif)


## 処理の流れ

1. 作ったアプレット（.app）起動
2. gpxファイルをアプレット（.app）にドラッグ&ドロップ
3. 上下左右の選択ボックスが現れるので選ぶ
4. 選択された方向によりgpxファイルを上書き
5. XcodeのSimulate Locationにあるgpxファイル名をクリック

以降、3〜5をループ。

## コード

コード量は100行程ですが、雑に書いたので主要な箇所だけ。

``` xxx.js
// ドロップされた時に実行されるハンドラ
const extensionsToProcess = ["gpx"];
const typeIdentifiersToProcess = [];
function openDocuments(droppedItems) {
    for (const item of droppedItems) {
        const alias = systemEvents.aliases.byName(item.toString());
        const extension = alias.nameExtension();
        const fileType = alias.fileType();
        const typeIdentifier = alias.typeIdentifier();
        if (extensionsToProcess.includes(extension) || typeIdentifiersToProcess.includes(typeIdentifier)) {
              const path = Path(item.toString().slice(1));
              changeGpx(path);
        }
    }
}
```

``` xxx.js
// gpxファイル読み込み
const finderApp = Application.currentApplication();
finderApp.includeStandardAdditions = true;
const readFile = finderApp.openForAccess(path);
const textGpx = finderApp.read(readFile, {as:"text"})
finderApp.closeAccess(readFile);
```

``` xxx.js
// gpxファイル書き込み
const gpxString = `<?xml version="1.0" encoding="utf-8"?>
    <gpx version="1.1">
    <wpt lat="${lat}" lon="${lon}" />
</gpx>`
const writeFile = finderApp.openForAccess(path, {writePermission:true});
finderApp.setEof(writeFile, {to:0})
finderApp.write(gpxString, {to:writeFile, as:"text"})
finderApp.closeAccess(writeFile)
```

``` xxx.js
// Xcodeの Debug > Simulate > xxxをクリック
const xcodeApp = Application("System Events").applicationProcesses.byName("Xcode");
const target = xcodeApp.menuBars[0]
.menuBarItems["Debug"].menus["Debug"]
.menuItems["Simulate location"].menus["Simulate location"]
.menuItems[fileName];
target.click();
```

``` xxx.js
// chooseFromListでユーザーからの入力待ち
while(true) {
    const selectedItem = systemEvents.chooseFromList(DIRECTIONS, {
        withPrompt: "Please select the direction of travel :",
        defaultItems: [selectedDirection]
    })
    // Cancelの場合は終了
    if (!selectedItem) {
        break;
    }
    selectedDirection = selectedItem.toString();
    
    switch (selectedDirection) {
    	...
    }
}
```

## jxaのよかったところ

- JavaScriptで書ける！
- 簡単にGUIアプリが作れる！
- 環境構築のためのアプリ、外部のライブラリのインストールが不要！

ってことでプログラムやったことない人でも気軽に触れるのでおすすめ！（Linux、Windows、その他のユーザーには申し訳）

## 参考

[Mac Automation Scripting Guide: About Mac Scripting](https://developer.apple.com/library/archive/documentation/LanguagesUtilities/Conceptual/MacAutomationScriptingGuide/index.html#//apple_ref/doc/uid/TP40016239-CH56-SW1)