20200120のiOSに関する記事は8件です。

UITableViewでセルを選択不可にする方法

環境

swift 5
xcode 11.3

2020年1月20日現在

動機

簡単なのですが、すぐに忘れてしまうので。

メモメモ

方法

selectionがNoneになっていれば選択することができなくなります。

スクリーンショット 2020-01-20 21.35.37.png

スクリーンショット 2020-01-20 21.35.45.png

コードだと

コードだと以下のように書くようです。

self.tableView.allowsSelection = false
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

signin with apple 実装するときの注意点まとめ

対応バージョン

iOS13以上、iOS13以下は対応しないため、別々のデザイン準備する必要があります。

取得できるユーザーデータ

  • email
    • ユーザーの選択でランダム生成されたメール渡せる可能性があります
  • full name
    • ユーザーの編集可能で、apple id登録された名前とは限らない

https://developer.apple.com/documentation/authenticationservices/asauthorizationappleidcredential?language=objc

sign in 初回と2回目の違い

sign in 初回はメールと名前のユーザーデータ取れますが、その以後sign inする場合は取得できなくなります。
初回取得成功後key chainなどに保存し、登録成功後削除したほうが一番無難。

 let request = ASAuthorizationAppleIDProvider().createRequest()
 request.requestedScopes = [.fullName, .email]
 let controller = ASAuthorizationController(authorizationRequests: [request])
 controller.delegate = self
 controller.presentationContextProvider = self
 controller.performRequests()

extension AppleSigninService: ASAuthorizationControllerDelegate {
    func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
        guard let credentials = authorization.credential as? ASAuthorizationAppleIDCredential else {
            let error = NSError(domain: "jp.huiping192.signInWithApple", code: -1000, userInfo: nil)
            signInSubject?.onError(error)
            return
        }

        // アプリ起動時ログイン状態チェックのためcredentials.user keychainに保持する
          saveUserId(credentials.user)
        // mailとnameある場合一時保持、登録成功後に削除
          saveUserInfo(nickname: credentials.fullName?.nickname, email: credentials.email)
    }

    func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
        // error handing
    }
}

AppleID使用停止検知

「設定」 -> 「{Apple ID}」->「パスワードとセキュリティ」-> 「Apple IDを使用中のApp」 -> 「{app name}」-> 「Apple IDの使用を停止する」

ユーザーは上の手順でSign in with Apple使用停止することが可能なので、アプリ側にチェックする必要があります。

  • アプリ起動時
ASAuthorizationAppleIDProvider().getCredentialState(forUserID: appleUserID) { credentialState, _ in
            if credentialState != .authorized {
                // logout
                User.current.logout()
            }
 }
  • アプリ起動中
NotificationCenter.default.rx.notification(ASAuthorizationAppleIDProvider.credentialRevokedNotification).subscribe(onNext: { _ in
                // logoutしとく
                User.current.logout()
            }).disposed(by: disposeBag)

AppleID使用停止後再度登録

新しいユーザーを扱い、token、ユーザー情報新しく取得できる。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

iOS Clean Architecture勉強会のまとめ

この文章は2020年1月21日に行われた「iOS Clean Architecture勉強会 sponsored by Sansan」という勉強会のまとめです。

発表内容

yimajo: 「クリーンアーキテクチャとiOSアプリ開発のためのVIPERと」

  • 依存関係逆転の原則(DIP)について
  • VIPER
    • VIPERの種類色々ある
    • VIPERはDIPを使ってない
  • DIPを使ってない場合の依存を取り除くには
    • Interactorごと取り替える
    • DBに依存したデータを表示するためのstructなどに置き換える

スライド

https://speakerdeck.com/yimajo/kurinakitekutiyatoiosahurikai-fa-falsetamefalseviperto

dotrikun: 「ゼロイチフェーズからのClean Architecture」

  • DeNAテックカンファレンスあります
  • 新規アプリでクリーンアーキテクチャは食い合わせ悪いのか
    • これまで3本は非CA
    • 4本目はCAを採用
  • AppRootViewController使ってる
    • 起動時
  • RouterにHUDいれてる
    • 悩んでる
  • Embedded Framework
    • UIではないEntity, UseCaseをEmbedded Frameworkで分けている
    • どこになにがあるかは慣れた
    • あとでWatchようにしたりするよりさきに分けておくと楽だった
  • ドメインロジックで切り出す
    • 他のアプリでも使える
  • クリーンアーキテクチャで先に作る「技術的投資」
    • 大きな会社のプロダクトなのでリターンが見込めそう
      • スタートアップだと厳しそう

スライド

https://speakerdeck.com/dotrikun/ios-ca

ChaaaaaaaaaaanU: 「VIPRE + MicroViewController を組み合わせて大きな機能を実装した話」

  • Sansan株式会社でSansanアプリを作ってる
  • 人物詳細
    • かなりリッチな画面(機能が多い)
    • 1つのVIPERモジュールではきつい
      • なのでMicroViewController使う
      • 各ViewControllerの中にVIPERの構成
        • Routerがなかったりする
      • MicroViewControllerのInstantiatableプロトコルはVIPERのRouterと役割がかぶる
        • 中途半端に両方を使わない

スライド

https://speakerdeck.com/yuichirokato/ju-da-naji-neng-wo-viper-plus-microviewcontroller-deiigan-zinishi-zhuang-sitahua

LT5分 kageroupro44: 「クリーンアーキテクチャ導入が、 どのような作業に影響を及ぼすのか考察」

  • インターンでfancというアプリ作ってる大学三年生
  • クリーンアーキテクチャ導入後
    • レイヤーやクラスが責務によって分かれた
      • 担当ワケできたので作業の短縮できた
    • 開発者感共通認識
      • 共通認識があるので全体的にスピードが上がった
    • 実装に統一感が生まれた
    • ファイルが増えた

スライド

https://speakerdeck.com/yutonakano/kurinakitekutiyadao-ru-ga-dofalseyounazuo-ye-niying-xiang-woji-bosufalsekakao-cha

hirothings:「VIPER with アーキテクチャ選定 実践入門」

  • VIPER以前の課題
    • ViewControllerで個別に遷移してた
    • プレゼンテーションロジックとデータ用のロジックが混在
  • 選定(VIPERに至る)
    • データバインディングは必要なし(インタラクティブいらない)
    • DBもなし
    • サンプルを作ったりして選定した
  • VIPERにしてよかったこと
    • ユニバーサルリンクからでもRouter使って画面表示が楽
    • iOSアプリ設計パターン(Routerの記述がいい)
    • テストしやすい実装を後押ししてくれる
    • 単体テストのはじめというスライドが良い
  • VIPER良い点
    • 層が分かれているので担当が分かれている
    • Embedded Framework
      • UIに関連する/しないでフレームワーク分割
        • 正しさよりも影響範囲で分けた
  • CM
    • 個人で作ってます
      • 作りはMVC
        • アプリの成長によってアーキテクチャを選定するのでクリーンアーキテクチャじゃない

スライド

https://speakerdeck.com/hirothings/viper-architecture

takasek: 「モバイルアプリにおける『中心』とは何か」

  • 中心とは?
    • 創界山!!
  • クライアントアプリはハブ
  • JSONの色付けは難しい
  • クライアントアプリの「ドメインロジック」は「エンティティ=中心」にあるとは限らない
  • CA本19章
    • 方針はさらに小さな方針に分離される

スライド

https://speakerdeck.com/takasek/20200121-the-center-of-the-client-number-ios-ca

座談会での質問

参加者の皆さんに頂いたアンケートから、発表者に質問に答えてもらいました

質問: Routerの呼び出しはenumだけだと他のパラメータどうしてるんだろ

  • ChaaaaaaaaaaanU
    • 情報はenumに入れている
      • コールバックもある
    • ボイラープレートはenumに吸収させたい

質問: 個人アプリでCA導入しようと思うきっかけがあれば教えてほしいです。

  • hirothings
    • アプリの複雑性よりも上位の問題が気になるのでCAでやってない
    • サーバサイドを気にしている
    • サーバサイドはテスト書いている
    • Firebaseだから?
    • そう
      • お金がかかわるから
      • NoSQLでセキュリティ・ルールが必要

質問: CA初学者にCAの概念と、実際の実務での差分のうまいフィッティングがあれば教えてほしいです。

  • 役割を考えるとシンプル
    • アプリに関係ない部分が外側にある
    • 外の世界をつなげるとこ
      • それで4つの世界
        • アプリに関係ある/ない/糊/外側
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ダークモードとは何か?各OSの設定方法からiOS/Androidアプリの対応方法まで

はじめに

勉強会をご覧の皆さま

元々のテーマは「10分でわかるダークモード対応」でしたが、あちこち調べているうちにページ数が30を超えてしまい、「10分ではわからないダークモード対応」になりました?‍♂️

20分には収めます


ダークモードとは?

OSシステムレベルで設定可能な、画面表示色の設定です。
light_and_dark.png
Light Modeが従来通りの白基調な画面、Dark Modeは黒基調な画面です。


何が明るく/暗くなるの?

特定の何に適用すべきという法則は無いようですが、閲覧者に見せたいコンテンツ以外のウィンドウ枠、背景などに対して適用されることが多いようです。

もちろん、メインコンテンツ(テキスト色など)も背景色に応じて調整する必要があります。


ダークモードにすると何がいいの?

  • 目へのダメージを抑える
    • 眩しい画面を見ることによるドライアイ頭痛、メラトニン抑制による不眠など
  • バッテリーの持ちが長くなる
    • OLEDスクリーンで輝度が100%の場合、DarkはLightと比較して約60%のエネルギーを節約。輝度が50%の場合、約15%節約(YouTubeアプリで計測)
  • 背景は明るいより暗いほうが、メインのコンテンツを目立たせ、作業に集中しやすくする

ダークモードにする場合のデメリットや注意点

  • 直射日光の下などの明るい場所で読みづらい
    • ナイトモード(ブルーライトカットの)と同じように、日没〜日の出までダークモードとする設定が用意されている
  • テキスト色と背景色の逆転にOCRが追いついていない
    • ダークモードで撮ったスクショをGoogle翻訳にかけても(現時点では)翻訳してくれない?

ダークモード対応OS

  • Windows 10 version 1903〜
  • Mac OS Mojave(10.14)〜
  • Android 10〜
  • iOS 13〜

ダークモード設定方法

  • Windows
    • スタート -> 設定 -> 個人用設定 -> 色
  • macOS
    •  -> システム環境設定 -> 一般 -> 外観モード
  • Android
    • 設定 -> ディスプレイ -> テーマ
    • Zenfoneの場合は 設定 -> ディスプレイ -> システムカラースキーム
    • クイック設定パネルに追加したい場合は 画面上端を下にスワイプ -> ?
  • iOS
    • 設定 -> 画面表示と明るさ -> 外観モード
    • コントロールセンターに追加したい場合は 設定 -> コントロールセンター -> コントロールをカスタマイズ

iOS/Androidアプリでのダークモード対応方法(アプリエンジニア向け)


iOS

準備

  • Xcode 11以上のビルド環境
  • iOS 13以上の実機orシミュレーター

iOSダークモード対応は急務!!


まずダークモードの見え方を確認しよう!

StoryboardやXibのInterface Builder上でLight/Darkを切り替える

    • 画面中央下部

デバッグ実行中にLight/Darkを切り替える

    • 画面中央下部

Darkにして、どうなったか。弊社案件の場合

  • テキストが自動で白くなったが背景も白い。文字が読めない!
  • 背景が自動で黒くなったがテキストも黒(
  • 濃緑基調のグラフィックが黒い背景では見えづらい
  • QRコードが真っ黒黒助

何故そうなるのか

  • 場所によってiOS System Colorsを使ったり使わなかったりするため
  • 大人数のプロジェクトでありがちな統一感の甘さ
  • とはいえiOSのStoryboardを完璧な統一感で作った人は見たことありませんが…?

対応作業

カラーセットを使う場合

  1. ハードコードしている色をAssets CatalogのColor Setに移行する
  2. Color SetのAppearancesにてDarkを追加する
  3. Dark Appearanceにフォーカスを合わせ色設定する

  • 色は従来のsRGB方式以外に、iOS System Colorsも選択可能
    • darkTextColorsystemBackgroundColorなど
    • 使うとOS側が色の濃さを自動調整してくれる。便利!
    • 詳しくは参考記事の実践 iOS13ダークモード対応に、わかりやすく書かれています

カラーセットを使わない場合

  • アプリ起動中にLight/Darkを切り替えられても即反映させたいので、次のいずれかの方法で実装

  • dynamicColor方式
extension UIColor {
    private class func dynamicColor(light: UIColor, dark: UIColor) -> UIColor {
        if #available(iOS 13, *) {
            return UIColor { (traitCollection) -> UIColor in
                if traitCollection.userInterfaceStyle == .dark {
                    return dark
                } else {
                    return light
                }
            }
        }
        return light
    }

    public static var textColor: UIColor {
        return dynamicColor(
            light: UIColor(displayP3Red: 0, green: 9, blue: 11, alpha: 1),
            dark: UIColor(displayP3Red: 255, green: 246, blue: 244, alpha: 1)
        )
    }
}

  • dynamicProvider方式
extension UIColor {
    @available(iOS 13.0, *)
    convenience init(light: UIColor, dark: UIColor) {
        self.init {
            if $0.userInterfaceStyle == .dark {
                return dark
            } else {
                return light
            }
        }
    }

    @available(iOS 13.0, *)
    public static let textColor = UIColor(
        light: UIColor(displayP3Red: 0, green: 9, blue: 11, alpha: 1),
        dark: UIColor(displayP3Red: 255, green: 246, blue: 244, alpha: 1)
    )
}

こちらはSDKバージョンの制限を受けますが、initとして処理を書けて、定数をimmutableにできます。


Android

準備

  • Android Studio 3.3以上のビルド環境
  • Android 10(Q)以上の実機orシミュレーター

まずダークモードの見え方を確認しよう!

Design View上でLight/Darkを切り替える


* Night Mode -> Nightを選択


開発者向けオプションを使う

  • システム -> 詳細設定 -> 開発者向けオプション -> フォースダークのオーバーライド
  • アプリの実装を変えずダークモードをシミュレートできる

Darkにして、どうなったか。弊社案件の場合

  • Design View上では何も変わらなかった…
    • Android版は?android:attr/textColorPrimaryなどのシステムカラーを使っていなかったから
    • Androidチームはデザイン指示書に厳密に従ったので、システムカラーを使わなかった
  • でも、開発者向けオプションだといい感じのダークモードになった

対応作業

  1. styles.xmlcolors.xmlを別々に用意する
    • Light:res/values/*
    • Dark:res/values-night/*
    • 共通のものはLight側にまとめよう
  2. Darkの方には、夜間モードフォースダークを適用する(後述)
    • 2つの重ね掛けはできないらしい

夜間モード機能を使う

  • アプリを新規作成すると自動でTheme.AppCompat.Light系のテーマが適用されているが、Dark側のスタイルにはTheme.AppCompat.DayNightを適用する
res/values-night/themes.xml
<style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar" />

フォースダーク機能を使う

  • 各ビューを分析して自動でダークカラーに変えてくれる機能
  • 先述の開発者向けオプションを使った確認では、こちらがシミュレートされる
res/values-night/themes.xml
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="android:forceDarkAllowed">true</item>
</style>
  • 自動で変えたくないビューには、AppTheme以外のstyleを用意して適用すればよい

Androidのダークモードサポートは色々手厚い!

  • より詳しく知りたい場合、こちらを参照

WebViewの場合は?


まとめ

  • ダークモードは目とバッテリーに優しく、集中できる!
  • iOSは2020/04まで(03末?)にダークモードを対応するか、一時しのぎでLightに固定しなければならない
    • まずは動かしてみないと修正規模がわからない
  • Androidはフォースダークで対応するのが手っ取り早そう

最後に大事なこと

  • ダークモード対応はエンジニアファーストで提案しよう!
    • 顧客やPMは、iOS SDKの事情でダークモード対応が必要なんて知る由もない
  • 工数削減のために、自動調整してくれるシステムカラーは最大限活用しよう!
    • 活用すれば、20画面あっても半日で終わるから怖くない(ヤバいAppは知りません)
  • デザイナーにも必要な情報を公開しよう!
    • 一言「ダークモード版の素材と指示書お願いします」で受けてくれるデザイナーは奇跡の存在です(個人の所感)

やっぱり言わせてください

面倒くせー!!!


参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Swift で 画像 (UIImage ) の リサイズ と トリミング (切り抜き) を一度の処理で行う。

0.はじめに

Swift で画像の切り抜きとリサイズを一度の処理で行いたかったので、やってみました。

以下の記事を参考にさせて頂きました。

感謝 ♪♪♪

?‍♂️?‍♂️?‍♂️

1.コード

今回は、画像を 0.5 倍にリサイズしつつ、中心部分を正方形に切り抜いてみました。

    var _image: UIImage = image
    var compress: CGFloat = 0.5
    var oneside: CGFloat = _image.size.width < _image.size.height ? _image.size.width : _image.size.height
    let origin: CGPoint = _image.size.width < _image.size.height
        ? CGPoint(x: 0.0, y: (_image.size.width - _image.size.height) * 0.5 * compress)
        : CGPoint(x: (_image.size.height - _image.size.width) * 0.5 * compress, y: 0.0)
    UIGraphicsBeginImageContextWithOptions(CGSize(width: oneside * compress, height: oneside * compress), false, 0.0)
    _image.draw(in: CGRect(origin: origin, size: CGSize(width: _image.size.width * compress, height: _image.size.height * compress)))
    _image = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()
■ リサイズ

まず、以下の処理で、出力先のサイズを指定します。

    var oneside: CGFloat = _image.size.width < _image.size.height ? _image.size.width : _image.size.height
    UIGraphicsBeginImageContextWithOptions(CGSize(width: oneside * compress, height: oneside * compress), false, 0.0)
■ トリミング (切り抜き)

そして、以下の処理で、画像をトリミング (切り抜き) します。

    let origin: CGPoint = _image.size.width < _image.size.height
        ? CGPoint(x: 0.0, y: (_image.size.width - _image.size.height) * 0.5 * compress)
        : CGPoint(x: (_image.size.height - _image.size.width) * 0.5 * compress, y: 0.0)
    _image.draw(in: CGRect(origin: origin, size: CGSize(width: _image.size.width * compress, height: _image.size.height * compress)))

重要なポイントは、

draw 関数の引数に指定する CGRect の値 (origin も、size も) を出力後の値で設定する

こと。

99.ハマりポイント

  • 上述しましたが、draw 関数の引数に指定に結構手間取りました…。

???

XX.まとめ

以上、ご参考になれば ♪♪♪

???

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CustomCellに置いたButtonの選択状態によってTableViewの処理を変える

タップしたButtonが乗ってるCellの情報をFirestoreに保存したい。
その想いから、こんなややこしい(?)記述方法になってしまいました。ご了承下さい。
Firestoreの部分は他記事にDelegate!

開発環境

・Xcode 11.3
・Swift 5.0

UIButtonのextensionを作る

CustomCell.swift
extension FaveButton {
    func switchAction(onAction: @escaping ()->Void, offAction: @escaping ()->Void) {
        switch self.isSelected {
        case true:
            //ONにする時に走らせたい処理
            onAction()
        case false:
            //OFFにする時に走らせたい処理
            offAction()
        }
    }
}

ButtonActionにDelegateを設定する

CustomCell.swift
import UIKit

protocol CellDelegate: AnyObject {
    func didTapButton(cell: CustomCell) //ON
    func didUnTapButton(cell: CustomCell) //OFF
}
class CustomCell: UITableViewCell {
    weak var delegate: CellDelegate?

@IBAction func didButtonTapped(_ sender: UIButton) {
        sender.switchAction(onAction: {
//TableViewController.swiftのdidTapButton()に委任
            self.delegate?.didTapButton(cell: self)
        },offAction: {
//TableViewController.swiftのdidUnTapButton()に委任
            self.delegate?.didUnTapButton(cell: self)
        })
    }
}
TableViewController.swift
import UIKit

class TableViewController: UITableViewController, CellDelegate /*追記*/ {

func didTapButton(cell: CustomCell) {
     print("ON")
    }

func didUnTapButton(cell: CustomCell) {
        print("OFF")
    }
}

参考

【iOS】UIButtonにON/OFFのスイッチ処理を1行で書く【Swift】

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Swift] IntやDoubleなどの数字オブジェクトを2倍にする関数でジェネリクスを使ってみた

概要

業務でInt型やDouble型を単純に2倍する関数を作りたい時に戸惑いましたのでググってみました。

    /// これを型ごとに作ると、関数が増えてしまって冗長なので書きたくない
    func multipleValue(_ value: Int) -> Int {
        return value * 2
    }

    func multipleValue(_ value: Double) -> Double {
        return value * 2
    }

    func multipleValue(_ value: CGFloat) -> CGFloat {
        return value * 2
    }

    multipleValue(2) // 4
    multipleValue(3.14) // 6.28
}

これをクールに一つの関数にまとめたいと思いました。
さてどうすればいいのかを考えるのが今回のテーマです。

ジェネリクスを使う

すぐに思いつくやり方は、ジェネリスクでパラメータを一つにまとめる方法です。

ジェネリスクはSwift のドキュメントでこう記されています。

英語版Swiftドキュメント

ジェネリクスの用法としては
[Swift]ジェネリクスについて

ジェネリック関数 | ジェネリクス | Swift

が参考になります。

それはいいとして、ジェネリクスを使ってこんな風に書きたいです。

    /// Tがジェネリックパラメータ
    func multipleValue<T>(_ value: T) -> T {
        return value * 2
    }

    multipleValue(2) // 4
    multipleValue(3.14) // 6.28
}

これでいけるかと思ったのですがビルドエラーになってしまいました。

image.png

エラーの内容は

Binary operator '*' cannot be applied to operands of type 'T' and 'Int'

どうやらジェネリクスに二項演算子「*」などのoperatorが使えないみたいなエラーでした。

そのため、てっきりジェネリクスで数値を2倍にできないのかと諦めかけましたが、
エラーの文章からググってみましたら解決策が見つかりました。

Binary operator '+' cannot be applied to two 'T' operands

ということで Numeric protocol に準拠させたら使えるそうです。

    /// Tがジェネリックパラメータ
    func multipleValue<T: Numeric>(_ value: T) -> T {
        return value * 2
    }

    multipleValue(2) // 4
    multipleValue(3.14) // 6.28
}

これで目標のあらゆる数値を単純に2倍にする関数が作れました。

Numeric とは何なのか

Numeric

乗算をサポートする値を持つ型だそうです。

Numericプロトコルを汎用制約として使用すれば、標準ライブラリ内の任意の数値型を操作する関数が作れるようになるとの事でした。

これで数値を操作する汎用メソッドが作れます。

と調べた後にこれについて詳しい資料がありましたので最後に貼って終わります。

Protocol-Oriented Integers に想うジェネリックプログラミングの未来

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React Native体験入学【環境構築】【標準コンポーネントの使い方】【リリースまで】

最近までNext.jsの入門してブログシステム作ってたけど、どうもwebpack周りで詰んでしまったのでもう少し実戦練習できることをやってみようと思ってReact Nativeを始めることに。あまりNext.jsに向いてないブログシステム作るより、ガッツリReact使いまくるアプリ制作でコーディングしまくりたい。

とりあえずReact Nativeの基本情報と、環境構築、ドキュメントやリファレンスの流し読み、そして簡単なアプリを作ってみようと思う。予定は簡単な「ダイス」アプリ。できればリリースするところまで経験しておきたい。

目次(暫定)

  1. 環境構築
    1. React Nativeとは(クロスプラットフォーム開発環境)
    2. Reactとは(UI構築のためのJSライブラリ)
    3. Expoとは(OSに依存しないビルド環境)
    4. 統合開発環境
      1. Xcode
      2. Android Studio
    5. 開発ツールのインストール
      1. Homebrew
      2. Node.js
      3. Watchman
      4. react-native-cli
    6. 動作テスト
  2. 仕様
    1. 標準コンポーンネント
    2. 標準API
    3. StyleSheet
    4. HTTP通信
    5. アニメーション
    6. データの保持
    7. 画面遷移(navigation・pagenation)
    8. 標準UI(React Native Elements)
  3. ビルド・リリース
    1. Google Play
    2. AppStore
    3. デバッグとアップデート

React Nativeとは

  • Facebookが開発したクロスプラットフォーム開発フレームワーク
  • FlutterみたいなやつのReact版
  • 同じコードでWeb・iOS・Androidアプリが作れる
  • OSのAPIの仕様の差をフレームワークレベルで抽象化することで共通化
  • JavaScriptとReactの知識があればモバイルアプリを作れる

Reactとは

UI構築のためのJSライブラリ。コンポーネントは状態を持ったviewの単位。Reactではコンポーネントを組み合わせてUIを構築する。その辺はReact.jsの方の公式ドキュメントなどで勉強すべし。

コンポーネントライフサイクル

これはいずれ理解しないといけないややこしい部分。数が多いのでまた今度気合入れて勉強しとく。

  • ReactDOM.render
  • constructor()
  • getInitialState() 非推奨。constructor()推奨。
  • componentDidMount()
  • componentWillUnmount()
  • shouldComponentUpdate()
  • getSnapshotBeforeUpdate()
  • componentDidUpdate()
  • componentDidCatch()

Expoとは

  • OSに依存しないビルド環境
  • スマホ用の開発環境アプリがある
  • 同じネットワークなら無線接続でテスト可能
  • 利用には会員登録が必要

Expo Snack

ブラウザ上でコードの動作をリアルタイムで確認できるツール。ReactのCodePenやCodeSandboxのようなもの。

アプリの実行方法は2つ

実機で動かすのと、シミュレータで動かすもの。

実機で動かすときは、Expo.ioからプロジェクトを開始したら表示されるQRコードを、スマホのExpoアプリで読み取れば起動する。

シミュレータで動かすときは、expo-cliというコマンドラインツールをPCにnpmインストールして、expo initコマンドを実行することでExpoプロジェクトに接続可能。ただしreact-native initコマンドとは異なることに注意。

コマンドラインからでもexpo startコマンドでQRコードから実機接続できる。また、このときにiを入力すればシミュレータが起動する。

統合開発環境

実機を持ってなくとも新旧機種を問わず動作テストできる環境を構築する。それにはXcodeとAndroid Studioといった統合開発環境をインストールすればいい。ただしiOSアプリの開発はMacOSでしかできない。以下、必要なツールをリストアップしておく。

Xcode

Android Studio

  • Java(開発言語)
  • JDK(Java開発キット)
  • SDK(ソフトウェア開発キット)
  • AVD(Android仮想デバイス)

その他

  • Homebrew(パッケージマネージャ)
  • Node.js(非同期のJSライブラリ)
  • Watchman(ファイルシステムの監視ツール)
  • react-native-cli(コマンドラインツール)
  • Expo

動作テスト

公式ドキュメントを参考に一通りやってみる。

各種インストール

環境はMacOS & iOSを選択。そしてXcodeをインストールすることでHomebrewが使えるようになる。

$ brew install node
$ brew install watchman
$ sudo gem install cocoapods
$ npx react-native init MyTestApp

このとき、react-native-cliをグローバルインストールしなくともnpxコマンドを使えばreact-native initコマンドが使える。下記コマンドはnpxを使わない例。

$ npm install -g react-native-cli
$ react-native init MyTestApp

シミュレータ起動して試運転

アプリをシミュレータで起動するコマンド。

$ cd MyTestApp
$ npx react-native run-ios

スクリーンショット 2020-01-19 20.51.24.png

App.jsを編集して保存したらホットリロードされる。

スクリーンショット 2020-01-19 20.52.00.png

次に公式ドキュメントのHello WorldコードをApp.jsにコピペして保存してみる。ここからは普通のReactのコーディングだと思えばわかりやすい。

App.js
import React, { Component } from 'react';
import { Text, View } from 'react-native';    // react-native標準コンポーネントのインポート

export default class HelloWorldApp extends Component {
  render() {
    return (
      <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
        <Text>Hello, world!</Text>
      </View>
    );
  }
}

スクリーンショット 2020-01-19 20.52.12.png

ちょっとだけ自由に編集してみた。まずrootディレクトリにpublic/を作成し、profile.pngを配置。そしてApp.jsImageコンポーネントをインポートのところに追加し、render()の中にpropsやstyleを与えた<Image />を記述。ついでに<Text>のフォントサイズのstyle追加とテキストを変更してみた。レイアウトは<View>コンポーネントのstyleでセンタリングされて表示される。

import React, { Component } from 'react';
import { Text, View, Image } from 'react-native';

export default class HelloWorldApp extends Component {
  render() {
    return (
      <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
        <Text style={{fontSize:30}}>お絵描きホーホー論</Text>
        <Image style={{width: 100, height: 100}} source={require('./public/profile.png')} />
      </View>
    );
  }
}

スクリーンショット 2020-01-20 1.36.19.png

標準コンポーネント

React Nativeのコンポーネントの構造についてサッと頭に入れておくと知識を蓄積しやすくなるかも。下図は公式サイトのトップページにある図解。React Nativeではいくつかの標準コンポーネントを提供しており、それをツリー構造で配置することでUIを構築し、そのReactコンポーネントはネイティブなコードをラップしているため、ネイティブコードを一切触らずにJavaScriptでのアプリ開発ができる、という触れ込みが書かれている。

スクリーンショット 2020-01-19 23.21.49.png

スクリーンショット 2020-01-19 23.22.04.png

標準コンポーネントの種類については、公式ドキュメントのコンポーネントとAPIのリファレンスを参考。基本的な説明と、渡せるpropsの一覧が見れる。名称から用途が想像できるものもあるが、各プラットフォーム専用のコンポーネントもあるので要勉強(下記が全てではない)。

  • 基本コンポーネント
    • View
    • Text
    • Image
    • TextInput
    • ScrollView
    • StyleSheet
  • UI
    • Button
    • Picker
    • Slider
    • Switch
  • List Views
  • iOS Components and APIs
  • Android Components and APIs
  • Others
    • Activity Indicator
    • Alert

Viewコンポーネント

HTMLでいう<div>のような役割。要素を入れるコンテナとして、レイアウトを作るのに使える。

return(
  <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
    (中略)
  </View>
);

Textコンポーネント

テキスト表示用で、HTMLと違ってReact Nativeではこのコンポーネントを使わないとテキスト表示ができない。

return(
  <Text>Hello World</Text>
);

Imageコンポーネント

画像を表示する。画像ファイルパスはrequirepublic/などの静的ファイル用のディレクトリを参照するようになる。Imageコンポーネントはstyleでサイズ指定しなけれな表示されない。基本的には位置調整のため<View>コンポーネントに入れて配置する。

return(
  <Image style={{width: 100, height: 100}} source={require('./assets/sample.png')} />
  <Image style={{width: 100, height: 100}} source={{uri: 'https://facebook.github.io/reactnative/img/favicon.png'}} />
);
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む