なぜ作ろうと思ったか
仮想通貨大好きな友だちから「ウィジェットで各通貨の値段は確認できるけど資産を確認できないのは不便」という声が。
ランチ1回で買収されて作ってみた。
↓は既存のビットバンクのウィジェット
確かに各コインの値段はわかるけど自分の資産情報はない
作ったもの
アプリ側で表示したいコインとBitbankのPrivateApiを叩くためのApiKey、ApiSecretを保存

それをウィジェットで表示するもの

1つのコインの資産を見たいとリクエストされたので今回は1つのコインの総資産、現在の価格を表示
Today Extension
iOSではこのウィジェットのことをToday Extensionと呼ぶ。
ターゲットの追加や実装方法などは他の方もあげているので一旦スルー
自分が詰まったところ中心に書きます。
ウィジェットのサイズを大きくするには
よくある表示を減らす、表示を増やすを押したら広がるもの。
override func viewDidLoad() {
super.viewDidLoad()
self.extensionContext?.widgetLargestAvailableDisplayMode = NCWidgetDisplayMode.expanded
}
widgetLargestAvailableDisplayModeを設定して表示を増やせるようにし、
func widgetActiveDisplayModeDidChange(_ activeDisplayMode: NCWidgetDisplayMode, withMaximumSize maxSize: CGSize){
if (activeDisplayMode == NCWidgetDisplayMode.compact) {
self.preferredContentSize = maxSize;
}
else {
self.preferredContentSize = CGSize(width: 0, height: 100);
}
}
このように増やした際の高さを指定。
どのタイミングでAPIを叩けばいいのか
func widgetPerformUpdate(completionHandler: (@escaping (NCUpdateResult) -> Void)) {
completionHandler(NCUpdateResult.newData)
}
ウィジェットが表示されるたびにwidgetPerformUpdate
が呼ばれる。(viewDidAppearてきな感じ。。?)
ここでAPI叩いた結果に対してNCUpdateResult
に値を渡してあげる。
NCUpdateResultNewData - 内容が入れ替わったのでビューの再描画が必要
NCUpdateResultNoData - 更新は不要
NCUpdateResultFailed - 更新処理中にエラーが発生
UserDefaultsをアプリ間で共有
今回はアプリ側でコインとAPIの情報をUserDefaultsに保存。それをToday Extension側で読み込んでAPIを叩く必要があった。
TargetのCapabilities
を選択
新しいApp Groups
を作成し、両方のTargetにそのApp Groupsを設定
このApp GroupsでUserDefaultsのインスタンスを作成し、保存、読み込めばデータが共有される。
let defaults = UserDefaults(suiteName: "group.共通のID")
リリースする際などはApple DeveloperからApp Groupsを作成して〜〜などしないといけないので注意
PrivateAPIを叩くためのHMAC-SHA256署名
個人的に今回一番詰まった。。
BitbankのProvateAPIを叩くには 「UNIXTIME、リクエストのパス、クエリパラメータ」 を連結させたもの
をAPI Secretと使ってHMAC-SHA256で署名しなくてはならない。
今回は以下のライブラリを使用
cocoapods
でインストール
pod 'CryptoSwift'
以下のように署名して使用
private func makeAccessSignWith(accessKey: String, unixtime: String, path: String, queryParam: String) -> String? {
let unixTimeStr = self.makeHaederUnixTime(unixTime: unixtime)
let linkedStr = unixTimeStr + path + queryParam
var bytes: [UInt8] = []
bytes += linkedStr.bytes
let signedString = try? HMAC(key: "APISecret", variant: .sha256).authenticate(bytes)
return signedString?.toHexString()
}
しかし叩けど認証エラーが返ってくる。。。
署名の作成方法が間違ってるのかと思っていると意外なとこで原因判明
BitBankのAPIドキュメントのページで自分のAPIキーとAPIシークレットを入力すると実際にAPIを叩いて確認することができるのだけれどそこのUNIXTIMEが
なぜ100年前。。。
この変なUNIXTIMEで一度APIを叩いたことが原因でその後も認証エラーがでてたよう。
クライアントから叩く際にUNIXTIMEに1000掛けして解決
今後
いまは一個のコインしか表示してないので全部表示して資産も全部足した資産にしよう