Flutterのセットアップ手順をまとめてみた

インストール

Flutter公式よりインストールする

MacOS install

Flutterのインストールボタンがあるのでそれをクリックしてsdkをダウンロードする

f:id:qed805:20190225205510p:plain
flutter_setup

ダウンロードが完了後、頭を使わずに以下のコマンドを叩く(パスはどこでも可能)

 cd ~/development
 unzip ~/Downloads/flutter_macos_v1.0.0-stable.zip

すると何もしなくても /Users/tamappe/flutterの所にflutterのsdkが解凍されます。

Android Studioの設定をする

try! Swift Tokyo 2019 に参加してきたのでレポートを書いてみた

まず始めに

try! Swift Tokyo 2019 の主催者、スタッフの皆さま本当にこの2日間お疲れ様でした。

まだ明日の朝一からのWorkshopが残っていると思いますがTL関係は全部終わったかなと思います。

僕は基本的にエビングハウス忘却曲線で時間の経過と共に内容を忘れてしまいますので記録に残そうと思います。

(寧ろブログを書くことを忘れてしまうことの方が多い)

いやー、try! SwiftのLTは全体的にとても勉強になります。

スポンサー会社のブース周りも楽しみの一つですが、今回のコーヒーサーバーは非常に美味しかったです。

あと例年try! Swiftで提供されるお弁当がとても美味しかったです。

順番を追って特に勉強になったことを書いていこ

2nd day

今回のセッションで特に印象に残った部分を洗い出してみましょう。

次へつなごう— Extending a hand to the next generation of Apple developers

ラストのセッショントークのものです。

NetflixiOSエンジニアの方でした。

日英同時プレゼンが印象的 + 女性のYoutuber。マイノリティなエンジニアの人って確かにあまり見かけない感じ。

僕は相当偏った経歴のエンジニアだと自認しているけど、それでも日本の職場で例えば外国人のiOSエンジニアの方と一緒に仕事する機会はなかったかも。

あと日本だとやっぱりiOSエンジニアになるためのハードルは高いと思う。

普通の日本の会社だとそもそもMacを支給される所は少なく大体はWindowsのパソコンを支給される。

初めて買ったMacPCは2011年モデルMacBook Air13inchだったと思う。

それでも10万円はした。

Windowsだとその当時でも5万円くらいでも手に入るのだからやっぱりMac製品はそれだけで敷居は高い気がします。

ただそれでもこれからもiOSエンジニアは増えていってほしいしSwiftコミュニティはもっと大きくなってほしいと願っている。

Core Dataを守るために

個人的には一番勉強になったセッションだったかも。レベル的にはチュートリアル - 中級者。

CoreDataを使うアプリ限定の話しかもしれませんが、Dataを保存するときの処理はハマりどころである。

特にマイグレーション管理は初心者エンジニアだと概念を知らないためか設定しないこともあったり忘れがちな概念です。

データを保存するときはbackgroundを使うのは当り前ですが、複数の処理を同時に走らせた場合は設計が弱いとデッドロックになる非常にセンシティブな

実装ですがこのセッションではこの部分の設計を丁寧に説明してくれていました。

SwiftCheckで始めるProperty-based Testing

ユニットテストに関するセッションで非常に勉強になりました。

僕はexample-based Testingしか概念をわかっていませんでした。

こういう知らない概念を知ったときはまだまだ知らない領域が沢山あるのだなと思って勉強の意欲が出てくるので嬉しいですね。

配列のテスト観点でreversedの観点は意外と見逃しやすいですしreversedを2回すると元に戻るのは当たり前だけど

必要な観点だと思います。

これは例えの話でしたけどこういった観点もテストの一環に入るというポイントが非常に勉強になりました。

なんとなくどこまでテストで補填してやるかというのが重要な考えなのかも。

Swiftにおける音の成形

セッション中に音楽が流れる非常に目を覚めやすいセッションでした。

ランチ後だったことも含めて非常にタイミングよく頭を起こしてくれるセッションでした。

Swiftを使って音を調整するというテーマのセッションです。

音とUIのセンスはかなりいけていて見ていてとても楽しめる内容でした。

と、まあそんな感じで

明日はworkshopという事で朝も早いのでこの辺りで終わりにしたいと思います。

それでもやっぱりこのカンファレンスはとても楽しくて勉強になりますね。

スタッフのみなさん本当にお疲れ様でしたし非常に楽しかったです。

RxSwift+NotificationCenterの購読機能を使ってキーボードが被らない機能を実装する

概要

今回はNotificationCenterのRxSwiftについて解説していきます。

github.com

このページをみるとNotificationCenterにはnotificationのfunctionがあることがわかります。

ということは

NotificationCenter.default.rx.notification("", object: nil)

という書き方になります。こちらはnotificationの引数を省略した形になります。

わざわざなんでNotificationをRxSwiftぽく書くんだ!という意見はあると思いますが後で説明します。

NotificationCenterの基本形

では、まずはNotificationCenterの購読の基本形を書きます。

ViewController.swift

NotificationCenter.default.rx.notification(name, object: nil)
    .subscribe(onNext: { notification in
        // 処理内容
    })
    .disposed(by: disposeBag)

このようになります。

これはRxSwiftを使わないやり方だと

ViewController.swift

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        // 購読の登録
        NotificationCenter.default.addObserver(self, selector: Selector(("sample:")), name: NSNotification.Name(rawValue: "SampleNotification"), object: nil)
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        // 購読の解除
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: "SampleNotification"), object: nil)
    }
    
    @objc private func sample(notification: Notification) {
        // 処理内容
    }

と同じ実装になります。

これだとRxSwiftを使った方が購読の解除のコードが要らない分、簡単に書けますね。

今回実装する機能について

今回はラインだったりメッセンジャーアプリに付き物のキーボードを表示したときにLabelTextFieldが被らないようにする実装について見ていきます。

RxSwiftを使わなくてもできるやん!というツッコミは勘弁してください。

よく使う機能をRxSwift で書くとどうなるかを学ぶ方がコードの書き方が分かると思います。

cocoapodについて

念の為、podの環境についておさらいします。

cocoapod

# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

target 'RxSwitch' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!

  # Pods for RxSwitch
    pod 'RxSwift', '~> 4.0'  # 追加する
    pod 'RxCocoa', '~> 4.0'  # 追加する

  target 'RxSwitchTests' do
    inherit! :search_paths
    # Pods for testing
  end

  target 'RxSwitchUITests' do
    inherit! :search_paths
    # Pods for testing
  end

end

このように

  • RxSwift
  • RxCocoa

のみインストールします。

storyboardの構成について

では今度はstoryboardの構成について見ていきます。

f:id:qed805:20190310184840p:plain
notification_rx_1

ViewControllerにはUILabelUITextFieldのみを置きます。

UILabel@IBOutletの接続をしておきます。

f:id:qed805:20190310185003p:plain
notification_rx_2

UITextFieldも同様です。

f:id:qed805:20190310185116p:plain
notification_rx_3

今回はキーボードとの関係性の実装でUITextFieldの制約が重要になりますのでこちらの設定だけ確認しておきます。

f:id:qed805:20190310185226p:plain
notification_rx_4

これで準備が完了します。

ソースコードについて

今回はキーボードの対応ということもありますので少しコードが多くなります。

本当はもっと簡単な機能が具体例にいいのですが、今時のiOS開発でNotificationが必要になる箇所はプッシュ通知だったりキーボード対応だったりします。

ですので今回でまとめて解説します。

ViewController.swift

import UIKit
import RxCocoa
import RxSwift

class ViewController: UIViewController {
    
    @IBOutlet weak var label: UILabel!
    @IBOutlet weak var textField: UITextField!

    private let disposeBag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // UITextField とUILabelのtextのデータを紐づける
        textField.rx.text
            .bind(to: label.rx.text)
            .disposed(by: disposeBag)
        
        // キーボードが表示される時のNotificationを登録する
        NotificationCenter.default.rx.notification(UIResponder.keyboardWillShowNotification, object: nil)
        .subscribe({ notification in
            if let element = notification.element {
                self.keyboardWillShow(element)
            }
        })
        .disposed(by: disposeBag)
        
        // キーボードが消える時のNotificationを登録する
        NotificationCenter.default.rx.notification(UIResponder.keyboardWillHideNotification, object: nil)
            .subscribe({ notification in
                if let element = notification.element {
                    self.keyboardWillHide(element)
                }
            })
            .disposed(by: disposeBag)
    }
    
    /// キーボードが表示時に画面をずらす。
    private func keyboardWillShow(_ notification: Notification) {
        guard let rect = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue,
            let duration = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? TimeInterval else { return }
        UIView.animate(withDuration: duration) {
            let transform = CGAffineTransform(translationX: 0, y: -(rect.size.height))
            self.view.transform = transform
        }
        print("keyboardWillShowを実行")
    }
    
    /// キーボードが降りたら画面を戻す
    private func keyboardWillHide(_ notification: Notification) {
        guard let duration = notification.userInfo?[UIResponder.keyboardAnimationCurveUserInfoKey] as? TimeInterval else { return }
        UIView.animate(withDuration: duration) {
            self.view.transform = CGAffineTransform.identity
        }
        print("keyboardWillHideを実行")
    }
}

このようになります。

これで実機でビルドしてみてUITextFieldをタップしてみましょう。

無事にキーボードが表示されてUITextFieldが被らないことが確認できたら成功です。

今週は try! Swift 2019 のカンファレンスが開催されますね。

先週末は友人の結婚式で大阪に帰省してた

先週は高校時代の同級生の結婚式があったので週末だけ大阪に帰りました。

帰省の際にはいつもスーツケースは一つだけを持参して新幹線に乗って帰ります。

結婚式のために帰るので荷物はスーツ1着と愛用のMBP(MacBook Pro)と充電器をスーツケースの中に打ち込みました。

そして昨日の日曜日に東京に戻ってきたのですが、

結婚式後ということもあり気分が仕事モードに戻れていません。

あと2,3日くらい休みたい気分になってしまいました。

今まで仕事人間で仕事をしている時が楽しかったのに今では疲れが溜まるのみ。

さらに今はフリーランス的な生活ですが契約が今月末で満期終了となるので大きなタスクも振ってきません。

見事に今は気が抜けっぱなしの状態です。

風船に穴が空いてプシャーッと縮んだような感じです。

今週からtry!Swiftカンファレンスが始まるよ

まっ、帰りの新幹線で今週の勉強会用のプレゼン資料の準備ができたので移動時間は有意義に過ごせたからいいでしょう。

今週は年一のカンファレンス try! Swift が開催されるので全てのエネルギーをそこに注ぎます。

今日もずっとプレゼン資料の作成に一日終わりそうだし。

try! Swift 2019 で来月のブログネタを仕入れてくるとしましょう。

Flutter でのアプリ開発日誌を書き始めたい

try! Swiftが終わったら、やっとFlutterでの個人開発を再開できる。

来月からのブログ記事の予定は当分Flutterに関するエントリーを予定しています。

一つのコードでiOS / Androidの両OSをカバーできるってなんてステキだろうか。

いつもだったらSwiftでiOSを開発した後はKotlinでAndroidを書き直さないといけないのです。

iOSで修正する機能が発生したらAndroidも修正しないといけないのです。(逆もまた然り)

こんなもん一人でメンテナンスなんてやってられん。

そんなこんなですが、

今日はまだLT用のプレゼン資料を作成してトークの練習をして1日を終えるでしょう。

今週はiOSアプリエンジニアの方にとっては猛烈に忙しい1週間となるでしょう。

そして、try! Swift 2019 のスタッフのみなさん頑張ってください。

楽しみにしています。

では今週も頑張って行こう!

追記

タイトルに書いてますが明日のtry! Swift 関連のイベントに発表者として登壇してきます。

tryswifttokyo-aftertalks.connpass.com

話す内容はすでに決まっていますが、練習でプレゼン資料を話す練習をすると普通に10分ぐらいかかりました。

そのため今日の作業は話す内容を削る作業になります。

WKWebViewのRXデータバインディングを実装する

概要

今回はWKWebViewのRxSwiftのローディング処理について見ていきます。

実はRxSwiftにWKWebViewのものがないためかrxのプロパティがありません。

ただし公式がWKWebViewに対するライブラリを提供していますのでこれをインストールして貰えればrxが使えるようになります。

github.com

こちらをcocoapodでインストールすることでWKWebViewに対してrxが使えるようになります。

ただWKWebViewはiOS11未満をサポートしている場合storyboardにUIKitを置くとワーニングが出てしまいます。

そのためコード側でWKWebView を作成してviewに乗せるという処理をしていきます。

cocoapodのライブラリについて

今回はWKWebView用のライブラリを追加するのでcocoapodのpodfileを下のように変更します。

# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

target 'RxSwitch' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!

  # Pods for RxSwitch
    pod 'RxSwift', '~> 4.0'  # 追加する
    pod 'RxCocoa', '~> 4.0'  # 追加する
    pod 'RxWebKit' # 追加する

  target 'RxSwitchTests' do
    inherit! :search_paths
    # Pods for testing
  end

  target 'RxSwitchUITests' do
    inherit! :search_paths
    # Pods for testing
  end

end

RxSwiftの他にRxWebKitを追加しました。

これをインストールしないとWKWebView に対してrxが使えません。

ViewControllerのソースコードについて

今回はViewController.swiftのコード側だけの実装となります。

ViewController.swift

import UIKit
import RxCocoa
import RxSwift
import WebKit
import RxWebKit

class ViewController: UIViewController {
    
    private var webView: WKWebView! = {
        let configuration = WKWebViewConfiguration()
        return WKWebView(frame: .zero, configuration: configuration)
    }()
    private let disposeBag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()
        setupWebView()
    }
    
    private func setupWebView() {
        // Rxの実装
        webView.rx.url
            .subscribe(onNext: { url in
                if let url = url {
                    print("URL: \(url)")
                }
            })
            .disposed(by: disposeBag)
        
        // storyboard にないのでviewに乗せる
        self.view.addSubview(webView)
        
        // webViewのオートレイアウトを設定する
        webView.translatesAutoresizingMaskIntoConstraints = false
        self.webView.topAnchor.constraint(equalTo: view.topAnchor, constant: 0).isActive = true
        self.webView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0).isActive = true
        self.webView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0).isActive = true
        self.webView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0).isActive = true
        
        // URLの読み込み
        if let url = URL(string: "https://www.google.com/") {
            let urlRequest = URLRequest(url: url)
            webView.load(urlRequest)
        }
    }
}

各所に補足のコメントを記載しました。

注意点は今回はWKWebViewをコード上で生成しましたのでviewにのせてオートレイアウトを張ることです。

コードとしてみてみるとRxを使わないコードと似たような感じになりますね。

WKWebViewはブラウザ内でJavaScriptを実行したりするときにデリゲートを多用するのでそのときにRxの真価が発揮されます。

挙動を確認してみよう

これでアプリをビルドしてみましょう。

画面が表示されてGoogleのページが表示されたら成功です。

f:id:qed805:20190308001434p:plain
wk_webview_2

今回はこれで終わります。