React Native さわってみたメモ
今年のはじめにこんな記事がバズった。
批判的なコメントが多かったせいか、記事自体はもう消されてしまっている。
自分も数年前に Titanium を使ったことがあり、そんときは「Nativeで頑張ったほうが良さそう」と思って使うのをやめてしまった。ただ、その頃から状況も変わっているだろうし、この人の言っていることを無下に批判する気にはなれなかった。
そんなわけで、実際に自分の手で動かしてみることにした。以下はその時の作業メモ(自分用なので読みやすさは考慮してません)
動作環境
- react-native: 0.41.1
- Xcode 8.3
- Android Studio 2.2.3
作ったソースコード
https://github.com/koogawa/ReactNativeSample
インストール
Introduction · React Native に従って、Node、Watchman、React Native CLI をインストール。
brew install node brew install watchman npm install -g react-native-cli
サンプルプロジェクトの作成
iOS
react-native init AwesomeProject cd AwesomeProject
これだけで最低限の機能を備えたiOSアプリを生成してくれる。(言語はObjective-C)
react-native run-ios
を実行すれば iOS Simulator を起動してくれる。もしくは出力された xcodeproj を Xcode で開いて自分でビルドすることもできる。
ビルド自体は本当に簡単にできた。
cmd+d でデバッグメニューが出てくる。
出力されたコードを見てみる
デバッグメニューを出すのをどうやって実現しているのか気になったのでソースを追ってみると
RCTKeyCommands *commands = [RCTKeyCommands sharedInstance]; // Toggle debug menu [commands registerKeyCommandWithInput:@"d" modifierFlags:UIKeyModifierCommand action:^(__unused UIKeyCommand *command) { [weakSelf toggle]; }];
こんな感じでやっていた。cmdキーを検知できるの知らなかった。
AppDelegate も読んでみる。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { NSURL *jsCodeLocation; jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil]; RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation moduleName:@"ReactNativeSample" initialProperties:nil launchOptions:launchOptions]; rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; UIViewController *rootViewController = [UIViewController new]; rootViewController.view = rootView; self.window.rootViewController = rootViewController; [self.window makeKeyAndVisible]; return YES; }
index.ios.js から RCTRootView
を生成して self.window.rootViewController にセットしてる感じなのね。
ためしに index.ios.js に変更を加えて再度ビルドしてみたけど、AppDelegate に差分は出なかった。某クラスプラットフォームのように、単純に機械的なコードを吐き出してるわけでは無さそうだ。この辺はとてもシンプル。
Android
SDK Manager を起動して、必要なパッケージをインストール。
- Google APIs
- Intel x86 Atom System Image
- Intel x86 Atom_64 System Image
- Google APIs Intel x86 Atom_64 System Image
このとき Android SDK Build-Tools 23.0.1
にチェックが入ってないとダメ。
環境変数 ANDROID_HOME
にもパスをセットする必要がある。
export ANDROID_HOME=${HOME}/Library/Android/sdk export PATH=${PATH}:${ANDROID_HOME}/tools export PATH=${PATH}:${ANDROID_HOME}/platform-tools
最初、ここのパスを間違えて結構ハマった。
次に Android Studio から AVD Manager を起動して、エミュレータを起動しておくのがポイント。
AVD Managerは
android avd
のコマンドでも起動できる。
react-native run-android
でアプリを実行。
こんな感じで Android アプリもビルドできた。
タブバーを表示してみる
TabBarIOSの公式ドキュメント通り実装してみるが、何故かエラーが出る。。🤔
調べてみてわかったのだが、
var React = require('react'); var ReactNative = require('react-native');
みたいな書き方はすでに古くなっているらしい😩
Does React Native use require or import? - Stack Overflow
import React, { Component } from 'react'; import { AppRegistry, TabBarIOS, StyleSheet, Text, View } from 'react-native';
のような書き方に修正することで、なんとかビルドが通った。
見てるドキュメントが間違ってるのかもしれないけど、公式ドキュメントが最新になってないのはちょっと焦った😞
TabBarIOS
という名前なので、Androidの場合はどうするんだろう?という疑問が湧いたが、やはり同じことを考える人がすでにいた。
How to make Tab bar for Android like TabBarIOS in react native? - Stack Overflow
こうやってiOS用のコードとAndroid用のコードを別々に管理していくことになりそう。
所感
- ホントに簡単にアプリを作り始められる
- 公式ドキュメント通りやっても動かないことが多々ある
- 正しい情報を探すことになり、ここに多くの時間を割くことになりそう
- ビルドしてみないとエラーかどうかわからないのがつらい
- コードの補完機能がないのが地味につらい
- パフォーマンスとかはもうちょっと使ってみないとわからない
- iOS/Android のバージョンが上がったときに追従してくれるか不安
iOSアプリはXcode で、AndroidアプリはAndroid Studioで作りたいと思った。何を言っているのかわからねーと思うが(略
— Og🌗エンジニア🏝宮崎 (@koogawa) 2017年2月4日
お世話になったリンク
2016/11/29 #potatotips 35 (iOS/Android開発Tips共有会) @トレタ に参加してきたよ
昨日はトレタさんで開催された potatotips #35 (iOS/Android開発Tips共有会) に参加してきました。
とてもオシャレなオフィスでした。
社内にはリラックマさんの姿も。
バーカウンターの裏はこんな感じ。id:masuidrive さんにコーヒーを淹れて頂きました。ごちそうさまでしたm(_ _)m
いつものようにツイートもまとめておきました。
以下はiOSの発表メモになります。間違いなどあれば教えて下さい(遅刻してしまったため、最初の方はメモが取れておりません🙇)
目次:
トレタでのSwift 3 対応
y_koh さんによる発表(私が遅刻したためメモが取れず🙇🏻)
「来年のSwift 4では楽になるはず」
私も期待してます😇
MVVM で Protocol Oriented をやってみた話 iOS
kumapo さんによる発表(私が遅刻したためメモが取れず🙇🏻)
iOSアプリ開発者なら簡単にできる!! TouchBarにツイートを表示するTips
yimajo さんによる発表(私が遅刻したためメモが取れず🙇🏻)
yimajo さんには休憩中に Touch Bar を見せて頂きました!初めて見たので感動でした 😂
GitLab CI for iOS
ikamooon さんによる発表です。GitLab で CI をまわすお話でした。
GitLab CI を使うための Multi Runner の設定方法などを詳しく解説されていました。
Embedded Framework in Action
TachibanaKaoru さんによる発表です。
アプリ内のソースコードをプロセス間で共有する仕組みである Embedded Framework についてのお話です。実際に使う上でのメリット・デメリットなど、ノウハウが満載でした。
ちなみに、QAタイムでは Tachibana さんが発表に使われていたMacBook Pro の使用感に関する質問が相次ぎましたw
Popoverの実装比較
Yuta Hoshinoさんによる発表です。
PickerをPopoverスタイルでコード1行で表示できる SwiftyPickerPopover について、デモを交えながら解説されていました。
Firebaseのススメ
nafu003 さんによる Firebase のお話です。
Firebase は Crash Reporting 機能も統合しているため、クラッシュが発生したユーザがどんな行動をしていたか?なども分析することができるそうです。他にもデモを交えながら様々な機能を紹介されていました。
UIコンポーネントを磨く
Ryota Hayashi さんによる発表です。
UIコンポーネントを開発する上でUIKitと同連携させていくか、というお話でした。ピンコードを入力するUIを例として、サンプルコードを交えながら解説されていました。華やかなUIをOSSで実現するのも良いけど。。の話はとても共感できました。
所感
今日の #potatotips は質疑応答も活発でいい感じでしたね!
— 所 友太 | Spinners Inc. (@tokorom) 2016年11月29日
tokorom さんも仰っていましたが、今日は質疑応答時間がアクティブで良い感じでした!(質問がひとつも出なかった発表はなかったのでは?)司会の方の進め方も上手かったのだと思います。
また、今回は噂の新型MacBook Proで発表される方が何人かいらっしゃいました。やはりUSB-Cのディスプレイアダプタまわりで苦労されている方が多かったように思えます。普及するまでにはしばらく時間がかかりそうですね。
ローディング中に画面ごと回転するライブラリを作った話
アプリが何らかの処理中にローディング画面を出すのは一般的だと思います。
これらに対抗して、画面全体がぐるぐる回るライブラリをネタで作ってみました。
インストール
CocoaPods でインストールできます。
pod "RollingProgressHUD"
使い方
RollingProgressHUD をインポートします。
import RollingProgressHUD
ローディング開始時に
RollingProgressHUD.show()
を呼び、ローディング完了時に
RollingProgressHUD.dismiss()
を呼ぶだけです。
デモ
ローディング中に画面ごと回転します。
目が回りそうですね(^q^)
エンジニア立ち居振舞い:自分のタスクよりメンバーのコードレビューを優先する
お題「エンジニア立ち居振舞い」 ということで自分も書きます。
以前、Twitterにつぶやいたのですが
自分のタスクよりメンバーのコードレビューを優先するの、自分の作業は止まるけどトータルで見るとスピードが上がる、と信じたい
— Og🌗エンジニア🏝宮崎 (@koogawa) 2016年7月25日
自分のタスクに着手する前に、チームメンバーのコードレビューをするように心掛けています。
コードレビューが滞ると、次のような悪影響があると思っています。
- 他のメンバーが次のタスクに着手できない
- プルリクエストが消化されないうちにもメインのブランチはどんどん進んでいるのでコンフリクトが起こる
- →コンフリクトを直す手間が増える
- 誰が何をしているか把握しにくくなる
当然、自分の作業は止まってしまいますが、それよりも上に書いた悪影響の方がまずいと思っていて、ここを解決することで全体的には開発スピードが上がると思っています。
共感した立ち居振る舞い
- レビュー依頼はすばやく見る - Sexually Knowing - 全体的に共感です
- エンジニア立ち居振舞い: プルリクエストは全部見る - 平常運転 - 自分もすべてのコードレビューに目を通すようにしていますが、全部見ることはメンバーには強制していません。
- レビュワーや未来の自分を意識してプルリクエストを作る - stefafafan の fa は3つです - diffを小さめにするの大事!どんなに多くても500行は超えないようにしたい
RxSwiftを使ってfoursquareのベニューを取得するメモ(Swift 3.0版)
以前書いたこちらの記事がさっそくビルドできなくなっていたので、Swift 3.0 対応版としてリライトしました。
RxSwift のメリットを理解するには実際に使ってみるのが一番!ということで、とりあえず foursquare のベニューを取得するサンプルを作ってみました。
※RxSwift は絶賛勉強中なので間違ったことを書いている可能性が高いです。ツッコミ歓迎です!
動作環境
- Swift 3.0
- RxCocoa (3.0.0-rc.1):
- RxSwift (3.0.0-rc.1)
- SwiftyJSON (3.1.1)
- Xcode 8.0
APIクライアント
APIにアクセスする部分を作ります。戻り値を Observable<[Venue]>
にしているのがポイントです。
func search(query: String = "") -> Observable<[Venue]> { return Observable.create{ observer in let client = FoursquareAPIClient(accessToken: "YOUR_TOKEN") let parameter: [String: String] = [ "ll": "40.7,-74", "query": query ]; client.request(path: "venues/search", parameter: parameter) { [weak self] data, error in guard let strongSelf = self, let data = data else { return } let json = JSON(data: data) let venues = strongSelf.parse(venuesJSON: json["response"]["venues"]) observer.on(.next(venues)) observer.on(.completed) } return Disposables.create {} } } fileprivate func parse(venuesJSON: JSON) -> [Venue] { var venues = [Venue]() for (key: _, venueJSON: JSON) in venuesJSON { venues.append(Venue(json: JSON)) } return venues }
通信ライブラリは拙作 FoursquareAPIClient を使用しました。
ViewModel
ViewModel から先ほどの serch
を呼び出す部分です。
public func fetch(query: String = "") { client.search(query: query) .subscribe { [weak self] result in switch result { case .next(let value): self?.venues.value = value case .error(let error): print(error) case .completed: () } } .addDisposableTo(disposeBag) }
search
の戻り値が Observable<[Venue]>
なので、これを subscribe することができます。その中で、返ってくる値(ベニューリストなど)を Variable
型の venues にセットしています。この venues は ViewController から bind されるため、値が変更されるタイミングで何か処理を発火させることができるわけです。
ViewController
ViewController は30行程と、かなりスッキリしました。rx.items(dataSource: )
でベニューリストと TableView を bind しているのがポイントです。ViewModel のベニューリストに変化があるとTableViewがリロードされます。
import UIKit import RxSwift import RxCocoa class ViewController: UIViewController { @IBOutlet weak var tableView: UITableView! var viewModel = ViewModel() var dataSource = DataSource() var delegate = Delegate() let disposeBag = DisposeBag() override func viewDidLoad() { super.viewDidLoad() self.tableView.delegate = self.delegate self.viewModel.fetch() self.viewModel.venues .asDriver() .drive ( self.tableView.rx.items(dataSource: self.dataSource) ) .addDisposableTo(self.disposeBag) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } }
完全なソースコードはこちらです。
GitHub - koogawa/RxSwiftSample: RxSwiftSample
参考にさせて頂いた記事など
CocoaPodsに登録した自作ライブラリを更新するメモ
毎回忘れるのでメモ。
前提
- すでに自作ライブラリを CocoaPods に公開済み
最初にライブラリを公開する際は下記記事がとても参考になる。
手順
1. ライブラリを更新
変更内容を push しておく。
実際に pod install して使えるかテストしておくこと。ブランチ指定が便利。
pod 'FoursquareAPIClient', :git => 'https://github.com/koogawa/FoursquareAPIClient.git', :branch => 'develop'
1. podspec ファイルを編集
s.version
を上げるのを忘れずに。
2. git にタグ追加
$ git tag -a 2.0.0 -m 'Compatible Swift 3.0' $ git push origin 2.0.0
3. podspec をバリデーション
$ pod spec lint
なんか怒られたら直す。
Swift 3対応でちょっとハマったので下の方に対処法を書いておいた。
4. CocoaPodsへ公開
pod trunk push FoursquareAPIClient.podspec
トラブルシューティング
困ったらとりあえず pod を最新に上げてみる
$ sudo gem install cocoapods
Swift 3 対応
pod spec lint
したら次のエラーが出た。
Check dependencies “Use Legacy Swift Language Version” (SWIFT_VERSION) is required to be configured correctly for targets which use Swift. Use the [Edit > Convert > To Current Swift Syntax…] menu to choose a Swift version or use the Build Settings editor to configure the build setting directly. “Use Legacy Swift Language Version” (SWIFT_VERSION) is required to be configured correctly for targets which use Swift. Use the [Edit > Convert > To Current Swift Syntax…] menu to choose a Swift version or use the Build Settings editor to configure the build setting directly. ** CLEAN FAILED ** The following build commands failed: Check dependencies (1 failure)
ググったら、同じように困っている人がいた。
Swift 3 CocoaPod does not pass lint - Stack Overflow
cocoapod を最新に上げて、.swift-version
ファイルを追加しないといけないらしい。
↑これは解決したけど、また新たなエラーが。
で解決。
Swift 5 対応
pod spec lint
したら次のエラーが出た。
** BUILD FAILED ** Testing with `xcodebuild`. -> FoursquareAPIClient (5.0.0) - ERROR | [iOS] xcodebuild: Returned an unsuccessful exit code. - NOTE | xcodebuild: note: Using new build system - NOTE | [iOS] xcodebuild: note: Planning build - NOTE | [iOS] xcodebuild: note: Constructing build description - NOTE | xcodebuild: error: SWIFT_VERSION '3.0' is unsupported, supported versions are: 4.0, 4.2, 5.0. (in target 'App') - NOTE | xcodebuild: error: SWIFT_VERSION '3.0' is unsupported, supported versions are: 4.0, 4.2, 5.0. (in target 'FoursquareAPIClient') Analyzed 1 podspec. [!] The spec did not pass validation, due to 1 error.
SWIFT_VERSION
に 3.0
なんか指定してないよ!と思ったけど、podspec ファイルに
s.swift_version = '5.0'
を指定してないのが原因?
さらに、Swift 3 対応のときに追加した.swift-version
ファイルも今は deprecated らしいので削除。
これでも解決しない場合は workaround だけど --allow-warnings
オプションで回避できるらしい。
リンク
「理科系の作文技術」を読んだ
以前、id:hyoshiok さんのブログで紹介されており、ずっと気になっていたので読んでみました。
対象とする読者
「私がこの書物の読者と想定するのは、ひろい意味での理科系の、わかい研究者・技術者と学生諸君だ。これらの人たちが仕事でものを書くとき――学生ならば勉学のためにものを書くとき――に役立つような表現技術のテキストを提供したい」。
序章で著者がこう述べているように、本書は主に理系層がターゲットとなっています。 しかし、実際に読んでみると、文書を書くすべての人におすすめできる内容になっています。
以下、印象に残った内容をいくつか紹介していきます。(数字は章を表す)
読者を意識する(2.3.4)
書くことに慣れていない人は、誰が読むのかを考えずに書き始める傾向がある、と著者は述べています。
読者が誰であり、その読者はどれだけの予備知識を持っているか、またその文書に何を期待し、要求するだろうかを、十分に考慮しなければならない。
これは技術ブログを書く際にも通じると感じました。読者がプログラミング初心者なのか、それとも基本的なことは理解している中級者なのか。読者のレベルによっても書く内容は変わってくると思います。
目標規定文(2.4)
自分は何を目標としてその文書を書くのか、そこで何を主張しようとするのかを熟考して、それを一つの文にまとめる。そういう文を、この本では目標規定文と読んでいました。
私はふだん、業務用の文書(Wikiなど)を書く際に、「これは何」という段落を一番上に用意するようにしています。そこに文書の目的を書くことが多いのですが、これがまさに目標規定文なのかな、と思いました。これがあるだけで、読者は読む・読まないの判断ができるようになります。
まぎれのない文を(8.3)
黒い目のきれいな女の子
この文はなんと 8通り に読むことができます。(ロゲルギスト共著『第四物理の散歩道』、(岩波書店、1969)、p226より)
「読むことができる」と表現しましたが、それだけ読者に誤解を与えてしまう可能性があるとも言えます。
この例は読点を入れることでまぎれがなくなります。
- 黒い目の、きれいな、女の子
- 黒い、目のきれいな、女の子
一つの文を書くたびに、読者がどういう意味に取るだろうかと、あらゆる可能性を検討するべきです。
字面の白さ(8.5.1)
次の2つの文を比べてみてください。
電源電圧の変動は普通0.1%程度だが、これでは普通 程度の周波数安定性しか得られない。我々の実験目的を達成するには、抵抗R1を調整して安定性を良くする必要がある。
電源電圧の変動はふつう0.1%程度だが、これではふつう 程度の周波数安定性しか得られない。われわれの実験目的を達成するには、抵抗R1を調整して安定性をよくする必要がある。
パッと見たとき、A. は全体として黒く、B. はそれとくらべて白く感じられると思います。字面の白さとはそういう意味です。無駄に漢字を使うと文章に難解な印象を与えてしまうので、適切な白さにすべきです。
手紙(10.1)
まだ e-mail も普及していなかった時代なので、手紙で要件を伝える方法についても書かれています。
印象的だったのが、10.1.3 本文 の
私なら、情報伝達に関係のない「拝啓、時下ますます・・・」は省いて〜
の部分。
メール文化になった今も「○○様 お世話になっております。△△株式会社の・・・」から始まるメールで溢れており、この辺は今もあまり変わっていないですね。
「読む」のではなく「話す」(11.1)
最終章では学会講演の要領についても書かれています。ここは「学会講演」を「勉強会での発表」に置き換えて読みました。
講演では原稿を「読む」のは禁物だ。聞く立場になってみればすぐにわかることだが、ひとが原稿を読みあげるのについていくには非常な努力がいる。
これは確かにその通りで、例えば「真空中で400℃、2時間の熱処理をした試料の表面に金の電極を蒸着し、・・・」というような複文は、読めばスラスラとわかっても、聞く側になると結構つらいものがあります。
この例は「資料はあらかじめ真空中で400℃、2時間の熱処理をします。その試料の表面に金の電極を蒸着し・・・」と単文に分割することで救われそうです。しかし、著者も述べているように、原稿をただ読みあげるのではなく、多少下手でも一生懸命「自分の言葉」でオーディエンスに話しかけることが重要なのだと思います。
おわりに
出版が1981年ということもあり、中にはOHP(オーバーヘッドプロジェクタ)の使い方など、今ではあまり使われなくなった内容も含まれています。しかし、それ以外の内容は30年以上たった今でも十分通用すると思いました。もっと早くこの本に出会いたかった!
理科系の〜と銘打ってはいますが、文章を書くすべての人におすすめしたい一冊です。