Blockscan JSON APIを使ってみる(Apple Watch) (2/2)

f:id:yzono:20120904110357j:plain

はじめに

今回はBlockscan JSON APIで取得した残高情報をApple Watchの画面に出力します。

目次

  • はじめてのApple Watch
  • iOSAppとWatchKit間のデータ連携
  • Blockscan Address API(アセット残高取得API)

はじめてのApple Watch

多くの先人のおかげでApple Watchのに関する情報は多数あります。iOS開発者なら1時間以内にWatchアプリを起動できます。

この動画は分かりやすく、まず動かしたいという人には良いです。

Apple公式のリファレンスもさっと読める量です。構成が分かりやすいのでこの画像を貼ります。

f:id:yzono:20150122154443p:plain

iOSAppとWatchKit間のデータ連携

Apple Watchの最初のつまずきは、PhoneとWatch間のデータ連携でした。

おそらくWatchKitから直接HTTPアクセスできないので、iOSAppでHTTPアクセスした内容をWatch側に連携したいです。iCloud連携、NSUserDefaultsなどでできそうですが、もっと簡単な方法はないのか... (Android Wearはより自由にできる)

とりあえず、Watch -> Phoneに対して通知することができるので、これをトリガーとしてデータを取るようにします。(本当はWatchからのトリガー無しでPhone -> Watchにデータを送りたいけどやり方わからず)

AppDelegate.swift

// WatchがopenParentApplicationを実行すると、このメソッドが受け取り処理をする
func application(application: UIApplication!, handleWatchKitExtensionRequest userInfo: [NSObject : AnyObject]!, reply: (([NSObject : AnyObject]!) -> Void)!) {    
  reply(["fromApp":"hoge"])
}

InterfaceController.swift

// ボタンアクション。Phoneに対しての通知して、結果を受け取ることができる
@IBAction func getJSONFromPhone() {
    WKInterfaceController.openParentApplication(["fromWatch": ""],
        reply: {replyInfo, error in
            ....
    })
}

Blockscan Address API(アセット残高取得API)

Blockscan Address API(アセット残高取得API)を利用します。指定したアドレスのアセット毎の残高を取得できます。

Satoshi単位ではなく、残高がそのまま取得できます。

リクエスト

http://api.blockscan.com/api2?module=address&action=balance&btc_address=16WhhnUUCZVvszFxsaCG3d6v77Qin1LErQ

レスポンス

{
  status: "success",
  message: "asset balance(s) found at 16WhhnUUCZVvszFxsaCG3d6v77Qin1LErQ",
  data: [
    {
      asset: "LOVE",
      balance: "999999999900",
      unconfirmed_balance: "0"
    },
    {
      asset: "ROSE",
      balance: "1000000000000",
      unconfirmed_balance: "0"
    },
    {
      asset: "XCP",
      balance: "1118.2517999",
      unconfirmed_balance: "0"
    }
  ]
}

ソースコード

AppDelegate.swift

import UIKit
import Alamofire

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        return true
    }
    
    func application(application: UIApplication!, handleWatchKitExtensionRequest userInfo: [NSObject : AnyObject]!, reply: (([NSObject : AnyObject]!) -> Void)!) {
        
        /* 
        var url = NSURL(scheme: "http", host: "api.blockscan.com", path: "/api2?module=address&action=balance&btc_address=16WhhnUUCZVvszFxsaCG3d6v77Qin1LErQ")
        var request = NSURLRequest(URL: url!)
        var data = NSURLConnection.sendSynchronousRequest(request, returningResponse: nil, error: nil)
        var json = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableLeaves, error: nil) as NSDictionary
        */
        
        // iPhoneシュミレータからHTTPアクセスできないので(なぜか)、とりあえず固定値を返す
        reply(["fromApp":"LOVE 999999999900:ROSE 1000000000000:XCP 1118.2517999"])
    }
}

InterfaceController.swift

import WatchKit
import Foundation

class InterfaceController: WKInterfaceController {
    
    @IBAction func getJSONFromPhone() {
        WKInterfaceController.openParentApplication(["fromWatch": ""],
            reply: {replyInfo, error in
                self.dispatch_async_main {
                    // Phoneから受け取ったデータを次画面(テーブルコントローラー)に渡して遷移する
                    self.pushControllerWithName("TableInterfaceController", context: replyInfo["fromApp"]!)
                }
        })
        
    }
    
    func dispatch_async_main(block: () -> ()) {
        dispatch_async(dispatch_get_main_queue(), block)
    }
}

TableInterfaceController.swift

import WatchKit
import Foundation

class TableInterfaceController: WKInterfaceController {

    @IBOutlet var tableView: WKInterfaceTable!

    override func awakeWithContext(context: AnyObject?) {
        super.awakeWithContext(context)
        
        // 受け取った値をsplitとして配列にする。(直接配列を渡す方法わからず。Swiftはもっと学ばないと..)
        let data = context as AnyObject? as? String
        let assets = split(data!, { $0 == ":" })
        
        tableView.setNumberOfRows(assets.count, withRowType: "TableInterfaceControllerRow")
        for (index, value) in enumerate(assets) {
            let row = tableView.rowControllerAtIndex(index) as TableRow
            row.titleLabel?.setText(value)
        }
    }

}

結果

f:id:yzono:20150122154513g:plain

まとめ

制約はありますが、アプリ開発のしやすさはAndroid Wearと比べて遥かに楽だと思いました。

本業の都合もありビットコイン2.0の話からだいぶ逸れてしまいました

参考

Apple Watchのアプリを開発してみた

【WatchKit】Apple Watch アプリのつくり方 & 全API解説

WatchKit Catalog(サンプルコード)を起動する方法

WatchKit アプリが開発できるようになりました!

Appleのサンプル Lister

WATCH の開発ツール WatchKit が公開されました

Watch KitでApple Watchアプリを作ってみる(Hello World編)

WatchKit Advent Calendar 2014