Posted at
TwilioDay 10

iPhone 紛失に備えた最高のソリューション

More than 1 year has passed since last update.

人間は年間を通して50回ほど愛用する携帯端末を紛失すると言われています。言われていますよね?

私の愛用する iPhone を代表とするApple端末には「iPhoneを探す」という本質的な機能がついていて、電源の入った端末のだいたいのGPS座標を表示したり、端末から音を鳴らして見つけやすくすることができます。

この機能は便利最高なのですが、最大の欠点は、ウェブブラウザもしくは他のApple端末経由でないと利用できないという点です。

例えば、旅行先でiPhoneを紛失した時などは、たいていの場合インターネットにアクセスする手段を失いますので近くのネットカフェに駆け込むとか、Apple端末を持つ周囲の人物に貸してもらうなどしなければなりませんが、そうこうしている間にも端末はあなたの手を離れ、どこか遠いところに行ってしまうかもしれません。

さて、そんな時には一体どうすればよいのでしょうか。答えはTwilioです。

Twilio は着電をすると任意の Web API をコールしてくれるように設定できます。そこで、 iCloud 上の iPhoneを探す 機能にアクセスし、あらかじめ登録した iPhone から音を鳴らす自作のウェブアプリを作成して、そこに Twilio からアクセスさせればよいのです。


手順(ウェブアプリ側)

僕はRubyがすきなので、Ruby + httparty で解説します。

iCloud ですが、真正面からアクセスしようとするとぶっちゃけ面倒なので、ウェブサイトを解析して非公開のAPIを叩きます。

require 'httparty'

# 認証情報の取り扱いには気をつけてください。
# 脆弱に作り込んだりハードコードした場合は思わぬところから認証情報が漏洩する可能性もあります。
ICLOUD_EMAIL = 'YOUR_APPLE_ID_HERE'
ICLOUD_PASSWORD = 'YOUR_APPLE_PASSWORD_HERE'

# 鳴らしたいiPhoneの名前です、インターネット共有の時にでてくるやつ
IPHONE_NAME = 'YOUR_IPHONE_NAME'

# iCloud.com APIクライアント代わりのメソッド
def icloud_request(method, url, **args)
unless @cookies
@cookies = HTTParty::CookieHash.new

# ログイン用のエンドポイントです
res = HTTParty.post "https://setup.icloud.com/setup/ws/1/login",
headers: {
"Origin" => "https://www.icloud.com"
},
body: {
apple_id: ICLOUD_EMAIL,
password: ICLOUD_PASSWORD,
}.to_json

# 今回割り当てられたエンドポイントです
@url = JSON.parse(res.body)["webservices"]["findme"]["url"]

@cookies.add_cookies(res.headers["Set-Cookie"])
end

args[:headers] = {
"Origin" => "https://www.icloud.com",
"Cookie" => @cookies.to_cookie_string
}
HTTParty.public_send method, "#{@url}/#{url}", **args
end

# 登録デバイス一覧が取得できるAPIです
res = icloud_request(:post, "fmipservice/client/web/initClient")

# 使いやすいように整形して取り出します
devices = Hash[res['content'].collect{ |device| [device['name'], device] }]
device = devices[IPHONE_NAME]

# iPhoneを鳴らすAPIです
icloud_request(:post, "fmipservice/client/web/playSound",
body: {device: device['id'], subject: 'alert'}.to_json)

ウェブアプリケーション側では、いたずら防止のために任意の認証を設けるとよいでしょう。

Twilioでは受電した際に入力した数字をパラメータとしてPOSTさせることが可能で、 Digits というフィールドに引き渡されます。

暗証番号を仮に 1234 とするなら、次のように認証が行えるでしょう。


sinatra

post '/findmyiphone' do

if params[:Digits] == '1234'
alert_iphone
erb :alerted
else
erb :auth_failed
end
end

これは、組み込んでみたサンプルです。


手順(Twilio側)

Twilio のアカウントを開設してください。(この手順は省略します)

TwiML Bin を作成します。中身はこんな感じでいきましょう。


findmyiphone

<?xml version="1.0" encoding="UTF-8"?>

<Response>
<Gather action="http://your-web-app/findmyiphone" method="POST" numDigits="4">
<Say voice="alice" language="ja-JP"> アイフォンをなくしたとき専用ダイアルです。暗証番号を入力してください。</Say>
</Gather>
</Response>

Twilioの電話番号を入手しましょう。(この手順は省略します)

入手した電話番号の設定しましょう。

CONFIGURE WITH には Webhooks/TwiML

A CALL COMES IN には TwiML を選択し、さっき作ったTwiMLを設定しましょう。

これで保存を押すと準備完了です。早速、Twilioの電話番号に電話をかけてみましょう。けたたましい音が鳴れば完成です。


今後の発展

これだけでは音を鳴らすだけですが、iCloud から帰ってくるデバイス情報には座標とかバッテリー残量なども含まれているので、座標から住所に変換したものをTwilio内で読み上げたりとか、遠隔でロックしたりとか色々できると思いますが、それらはこれを読んでいるみなさんの宿題とします。

あと、今も使える iCloud.com クライアントになる gem が見つからなかったので、それは気が向いたら作って公開するかもしれません。この手法でアクセスするとセッションが1分で無効になるのでそれが目下の課題です。