cordova xcodeのEnable Bitcodeを有効にする

cordovaアプリだとアプリがクラッシュすることはあまりないのかもしれないが。
が、プラグイン等が原因でクラッシュした際にクラッシュレポートを見てもdSYMsファイルがないと原因を特定するのが難しいことがあった。

cordovaのオプションで何かあるのかなと思ったが見つからず...

https://github.com/nrikiji/cordova-plugin-xcode-enable-bitcode
このプラグインいれればEnable BitcodeをYESにしてくれる

以上です

ios circleciでcarthageのキャッシュが効かなかった原因と対応

はじめに

CircleCI 2.0 + Carthage で carthage bootstrap に時間がかかる場合の解決方法 - Qiita
こちらを参考にcarthageのキャッシュを使ってcircleciでのビルド時間を短縮。が、とあるタイミングでキャッシュが上手く効いていないようだった。

circleciでは以下のような出力

・・・
*** Valid cache found for SVProgressHUD, skipping build
*** Invalid cache found for SwiftDate, rebuilding with all downstream dependencies
*** Invalid cache found for SwiftWebSocket, rebuilding with all downstream dependencies
*** Invalid cache found for SwiftyJSON, rebuilding with all downstream dependencies
*** Invalid cache found for SwipeMenuViewController, rebuilding with all downstream dependencies
・・・

restore_cacheとsave_cacheはちゃんと動いていそうだが、carthage bootstrapで「Invalid cache found for ・・・」となってしまう

steps:
  - checkout
  - restore_cache:
      key: ca-{{ checksum "Cartfile.resolved" }}
  - run:
      name: Carthage
      command: carthage bootstrap --platform iOS --cache-builds
  - save_cache:
      key: ca-{{ checksum "Cartfile.resolved" }}
      paths:
        - Carthage

結論

原因はxcodeのバージョンを10.0.0から10.1.0に上げたことだった。Carthage/Build/.xxxxx.versionのhash がrestore_cache時の値とcarhage bootstrap値で違った。xcodeのバージョン上げたから当然なのか。。キャッシュのキーにxcodeのバージョンも追加して解決。

steps:
  - checkout
  - run:
      name: Set Xcode Version
      command: echo `xcodebuild -version` > XCODE_VERSION
  - restore_cache:
      key: ca-{{ checksum "XCODE_VERSION" }}-{{ checksum "Cartfile.resolved" }}
  - run:
      name: Carthage
      command: carthage bootstrap --platform iOS --cache-builds
  - save_cache:
      key: ca-{{ checksum "XCODE_VERSION" }}-{{ checksum "Cartfile.resolved" }}
      paths:
        - Carthage

以上です

ios carhage_supportでcarthageのライブラリ管理

carthage_supportの使い方メモしておく。
Cartfileに記述した内容と「Linked Frameworks and Libraries」、「Run Script」の内容を手動で合わせるのを管理してくれる。

carthage_supportインストール

$ sudo gem install carthage_support

プロジェクトのルートにcarhage.ymlを作成

project_path:
  CarthageTest.xcodeproj

## Cartfileに記述する内容                                                                                                                                                                                          
github "Alamofire/Alamofire":
  ## Linked Frameworks and Librariesに追加する部分                                                                                                                                                                 
  - Alamofire.framework

github "Alamofire/AlamofireImage":
  - AlamofireImage.framework

プロジェクトのルートでコマンド実行

$ cd /path/to/MyProject
$ carthage_support setup

これで手作業で行なっていた以下の内容を行ってくれる
・Cartfileの作成
・「Linked Frameworks and Libraries」の設定
・「Run Script」の設定

以上です。

cordova carthage対応のライブラリを使ったプラグイン開発

Carthageを使ったライブラリを使用して開発されたCordovaプラグインをいくつか見つけた。が、導入方法はプラグインインストール後や`platform add ios`した後にXcodeからCarthageのお決まりの作業を行わなくてはならないようだった。

問題点は以下
・手間がかかる
・CI環境でビルドできない

cordova-plugin-carthage-supportプラグインを使えば解決

plugin.xml

<carthage>
  <cartfile>github "hoge/fuga" ~> 2.0</cartfile>
  <framework src="HogeSDK.framework"/>
  <framework src="FugaSDK.framework"/>
</carthage>

plugin.xmlに上記のように記述した場合、以下のようにCarthageを設定したのと同じ挙動となる

Cartfile

github "hoge/fuga" ~> 2.0

Linked Frameworks and Libraries

HogeSDK.framework
FugaSDK.framework

Build PhasesのRun Script

$(SRCROOT)/Carthage/Build/iOS/HogeSDK.framework
$(SRCROOT)/Carthage/Build/iOS/FugaSDK.framework

以上です

swift4 アプリのバージョン番号とビルド番号取得

// バージョン番号
Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion")

// ビルド番号
Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString")

参考
https://qiita.com/arthur87/items/802d17387ae46fb44fc2

rails actioncable + swiftでwebsocketのhello world

iOSでWebSocketを少し試す必要があったのでそのときの手順をまとめておく。サーバー側はRails5.2のAPIモードでActionCableを使う。

railsインストール

$ bundle exec rails new ac_test --api

Channel作成

channel作成

$ ./bin/rails g chnnel chat

ChannelはコントローラのWebSocket版と考える。そのままだけど、subscribeはクライアントからsubscribeのメッセージを受け取ったら呼ばれる。

app/channels/chat_channel.rb

class ChatChannel < ApplicationCable::Channel
  def subscribed
    stream_from "chat:message"
  end

  def unsubscribed
  end
end

接続してみる

ここまでできたらサーバーを起動してWebSocketクライアントで接続してみる。

‎WebSocket Client on the Mac App Store
GUIのソフトを探したところこちらのソフトが使いやすそうだった。

f:id:yoppy0066:20190108195942p:plain:w400
ws://192.168.1.109:3000/cable を入力して「Connect」をクリック

rails serverのコンソール

Started GET "/cable" for 192.168.1.109 at 2019-01-08 18:33:16 +0900
Started GET "/cable/" [WebSocket] for 192.168.1.109 at 2019-01-08 18:33:16 +0900
Request origin not allowed: ws://192.168.1.109:3000
Failed to upgrade to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: Upgrade, HTTP_UPGRADE: websocket)
Finished "/cable/" [WebSocket] for 192.168.1.109 at 2019-01-08 18:33:16 +0900

「Failed to upgrade to WebSocket...」と接続に失敗していることがわかる。原因は送信元のチェックで引っかかているようで、今回はテストのため全てのリクエストを許可する。

config/environments/development.rb

# すべての送信元からのリクエストを許可                                                                                                                                                                             
config.action_cable.disable_request_forgery_protection = true

サーバーを再起動して再度接続すると今度は「Successfully upgraded to WebSocket」と成功。

Started GET "/cable" for 192.168.1.109 at 2019-01-08 18:38:06 +0900
Started GET "/cable/" [WebSocket] for 192.168.1.109 at 2019-01-08 18:38:06 +0900
Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: Upgrade, HTTP_UPGRADE: websocket)

f:id:yoppy0066:20190108200016p:plain:w400
クライアント側もtype:welcomのレスポンスを確認できた。

subscribeしてみる

引きつづき接続したままの状態でsubscribeする

f:id:yoppy0066:20190108200031p:plain:w400
「Body」に以下のJSONを入力して送信ボタンのアイコンをクリック

{"command":"subscribe","identifier":"{\"channel\":\"ChatChannel\"}"}

railsのコンソールに以下が出力されれば成功

ChatChannel is transmitting the subscription confirmation
ChatChannel is streaming from chat:message

この状態で、ChatChannelのMessageにメッセージを送信してクライアント側でレスポンスを取得できるか確認する

./bin/rails console

$ ChatChannel.broadcast_to('message', 'hello')

レスポンスがあればクライアントの右側のペインに出力されるはずだが何も表示されないので失敗

ruby on rails - ActionCable.server.broadcast from the console - Stack Overflow
こちらの記事によると、別プロセスから実行する場合(rails serverとrails consoleは別プロセス)の場合、adapter: asyncは使えないらしい。記事の通り、config/cable.ymlの設定をasyncからadapterに変更する。

development:
  adapter: async
↓
development:
  adapter: redis
  url: redis://localhost:6379

Gemfileにredisを追加して./bin/bundle install

gem 'redis'

macにredis-serverがインストースされていれば redis-server で起動する。されてなければ「brew install redis」等でインストールする。再度、rails consoleからメッセージを送信すると今度はメッセージが受信できることが確認できた。
f:id:yoppy0066:20190108200113p:plain:w400

ここまででサーバー側の実装は完了とする。

Swiftでクライアントを実装する

GitHub - tidwall/SwiftWebSocket: Fast Websockets in Swift for iOS and OSX
シンプルに試せそうだったのこちらを使う。READMEに書かれているとおり、Carthageでインストールする。Carthageでのライブラリのインストールについてはこちらを参考に。

ViewController.swift

import UIKit
import SwiftWebSocket

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        func initializeWebSocket() {

            let request = URLRequest(url: URL(string: "ws://192.168.1.109:3000/cable")!)
            let ws = WebSocket(request: request)

            ws.event.open = {
                // 接続に成功したらsubscribe発行
                let json = """
{"command":"subscribe","identifier":"{\\"channel\\":\\"ChatChannel\\"}"}
"""
                ws.send(json)
            }

            ws.event.close = {_,_,_ in
                // 接続が切れたら再接続を
                DispatchQueue.main.asyncAfter(deadline: .now() + 10) {
                    initializeWebSocket()
                }
            }

            ws.event.message = {(response) in
                // メッセージ受信
                dump(response)
            }
        }

        // 接続
        initializeWebSocket()
    }
}

ほぼドキュメントに書かれている内容だが上記のようなプログラムを実行するとコンソールから動作が確認できた。ほとんどrails側の作業だった。。。チャンネルとストリーミングのところはあまり理解できてないのでチャットルームなり作って理解を深めたいと思う。とりあえず触りはこんなものかな。以上です。