iPhoneの実機で位置情報をシミュレーションする方法

ポケモンGOで位置情報偽装で不正アカウントがBANされ始めていますが、BANされる方法をご紹介します。
これから、ポケモンGOみたいな位置情報アプリを作れと言われたときに使える便利なデバッグ方法です。

iPhoneのGPSの位置情報はXcodeのSimulate Locationを使うとを偽装できます。
iOSの位置情報は端末内のすべてのアプリで共通になるため、他のiOSアプリにも影響を起こすことができます。

# 位置情報をシミュレーションする方法
## １．Xcodeで新規プロジェクトを作る

中身は空で良いのでSingle View Applicationを選択してプロジェクトを作成します。
<img width="1145" alt="スクリーンショット 2016-08-21 2.58.58.png" src="https://qiita-image-store.s3.amazonaws.com/0/7132/7740b9cc-c428-9db1-cbc9-1039630f72da.png">

## 2.AppDelegate.swiftにバックグランドでも処理を継続するよう書き加える

iOSの位置情報はアプリ内で共通ですが、Simulate Locationはアプリがサスペンドされると機能しなくなります。
そのためアプリにバックグランド継続処理を加えます。

```swift:AppDelegate.swift
import UIKit
import CoreData

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?
    var backgroundTaskID : UIBackgroundTaskIdentifier = 0

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        return true
    }

    func applicationWillResignActive(application: UIApplication) {
        self.backgroundTaskID = application.beginBackgroundTaskWithExpirationHandler(){
            [weak self] in
            application.endBackgroundTask((self?.backgroundTaskID)!)
            self?.backgroundTaskID = UIBackgroundTaskInvalid
        }
    }
}
```
backgroundTaskIDとapplicationWillResignActiveメソッドを追記しています。それ以外の部分はそのままでOK

## 3．実機でこのアプリを実行する

実機のiPhoneを選択して、アプリを実行します。
<img width="1283" alt="スクリーンショット 2016-08-21 4.37.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/7132/8e9fe837-02cc-e00e-8cc3-efb73ee1031e.png">

## 4.Simulate Locationを使用する

アプリを実行中に```Debug > Simulate Location```で移動先の都市を選択することができます。
試しにロンドンを選択してみます。
![スクリーンショット 2016-08-21 4.44.06.png](https://qiita-image-store.s3.amazonaws.com/0/7132/51fb1207-52ed-085a-b69e-a6c0ad752a26.png)

この状態でマップを開いてみるとロンドンにいることが確認できます。
<img width="320" alt="IMG_2106.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/7132/cef49a0d-2315-93b3-7a09-d14da7d7c958.png">

## 5.任意の位置情報に偽装する方法

任意の位置情報に変更するにはGPXファイルというものを作成します。
XML形式のファイルで緯度経度の情報を記述するだけのファイルです。

```xml:MyLocation.gpx
<?xml version="1.0"?>
<gpx version="1.1">
    <wpt lat="35.6575811" lon="139.7009455" />
</gpx>
```

このファイルには渋谷駅を指定しました。

そして```Debug > Simulate Location > Add GPX File to Project```からファイルを読み込むと、
２番目に新しく追加された項目増えているので選択します。

![スクリーンショット 2016-08-21 5.18.19.png](https://qiita-image-store.s3.amazonaws.com/0/7132/2032948b-5ba4-ec6a-c472-2a5ce6870e2c.png)

確認すると、先ほどGPXファイルで指定した渋谷駅に位置情報が書き換わっています。

<img width="320" alt="IMG_2108.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/7132/2d3a3e1d-e3d0-11c2-fad5-1ab5efd55beb.png">


# 位置情報を徐々に動かしていく方法

読み込ませているGPXファイルの内容を変更してもXcodeからSimulate Locationをクリックしないと、iPhone側の位置情報は書き換わりません。

そのためAppleScriptでXcodeのUIを操作します。

## 1.スクリプトエディタの補助アクセスを許可する

AppleScriptからMac上のUIを操作しようとすると、「```System Events でエラーが起きました：スクリプトエディタ には補助アクセスは許可されません。```」という内容のエラーメッセージが表示されてしまします。

まだ設定されていない場合は、```システム環境設定 > セキュリティとプライバシー > プライバシー > アクセシビリティ```で```アプリケーション > ユーティリティ > スクリプトエディタ.app```を許可してください。
<img width="780" alt="スクリーンショット 2016-08-21 5.47.47.png" src="https://qiita-image-store.s3.amazonaws.com/0/7132/5c98931a-befe-6b2f-76ea-e6f9d7ec550d.png">


## ２.GPXファイルを書き換えるスクリプト

このような感じでAppleScriptからGPXファイルを作り出します。

```applescript:changeMyLocation.scpt
set gpxfile to "/Users/{username}/Documents/works/{xcodeproject}/MyLocation.gpx"
set lat to 35.6575811
set lon to 139.7009455

set outputStr to "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
set outputStr to outputStr & "<gpx version=\"1.1\">"
set outputStr to outputStr & "<wpt lat=\"" & lat & "\" lon=\"" & lon & "\" />"
set outputStr to outputStr & "</gpx>"
	
open for access POSIX file gpxfile with write permission
write outputStr to POSIX file gpxfile as «class utf8»
close access POSIX file gpxfile
```

gpxfileのファイルパスは追加したGPXファイルのものに書き換えてください。

## 3.Simulate Locationをクリックするスクリプト

```applescript:changeMyLocation.scpt
tell application "System Events" to tell process "Xcode"
	click menu item "MyLocation" of menu 1 of menu item "Simulate Location" of menu 1 of menu bar item "Debug" of menu bar 1
end tell
```

## 4.徐々に位置情報を書き換え続けるループ処理をつくる

repeatでループし緯度と経度に１秒毎に0.001を加算するようにしました。
これで北東方向に進むようになります。

```applescript:changeMyLocation.scpt
set gpxfile to "/Users/{username}/Documents/works/{xcodeproject}/MyLocation.gpx"
set lat to 35.6575811
set lon to 139.7009455

repeat
	set lat to lat + 1.0E-3 -- +0.001
	set lon to lon + 1.0E-3 -- +0.001
	
	set outputStr to "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
	set outputStr to outputStr & "<gpx version=\"1.1\">"
	set outputStr to outputStr & "<wpt lat=\"" & lat & "\" lon=\"" & lon & "\" />"
	set outputStr to outputStr & "</gpx>"
	
	open for access POSIX file gpxfile with write permission
	write outputStr to POSIX file gpxfile as «class utf8»
	close access POSIX file gpxfile
	
	tell application "System Events" to tell process "Xcode"
		click menu item "MyLocation" of menu 1 of menu item "Simulate Location" of menu 1 of menu bar item "Debug" of menu bar 1
	end tell
	
	delay 1
end repeat
```

このコードをスクリプトエディタで実行します。
▶ボタンで実行、■ボタンで停止です。
![Group.png](https://qiita-image-store.s3.amazonaws.com/0/7132/b9c5cd9b-ec71-0f5a-a6cc-a2406040d70c.png)

実行して実機を確認すると動いていることが確認できました。

![Group.png](https://ssl-stat.amebame.com/pub/content/8265872137/user/article/unknown/unknown/316341258845424694/b38b140ea31ea571c8380a98868dd844/uploaded.gif)

# おわり
継続的に動かすのに慣れてないAppleScriptを使う必要がありますが、iOS側は簡単でしたね。
どのように使うかは自己責任でお願いします。

１つ問題があり、アプリを終了してもSimulate Locationで設定した位置情報が元に戻りません、再起動すれば元にもどるのですが、簡単に戻す方法が不明です・・・