メインコンテンツへスキップ

React Nativeで構築 - Build.comアプリ

·6分で読めます
Garrett McCullough
シニアモバイルエンジニア

Build.com はカリフォルニア州チコに本社を置き、住宅リフォーム用品のオンライン小売業者としては最大手の1つです。同チームは18年間強力なWeb中心のビジネスを展開してきましたが、2015年にモバイルアプリについて検討し始めました。少人数のチームと限られたネイティブ経験では、独自のAndroidおよびiOSアプリを構築することは現実的ではありませんでした。その代わりに、私たちは非常に新しいReact Nativeフレームワークに賭けることにしました。最初のコミットは2015年8月12日で、React Native v0.8.0を使用しました!2016年10月15日には両方のアプリストアで公開されました。過去2年間で、私たちはアプリのアップグレードと拡張を続けてきました。現在、React Nativeバージョン0.53.0を使用しています。

アプリはhttps://www.build.com/appでご覧いただけます。

機能

当社のアプリはフル機能で、eコマースアプリに期待されるすべての機能が含まれています。商品リスト、検索と並べ替え、複雑な商品の設定機能、お気に入りなどです。標準的なクレジットカード決済方法のほか、PayPal、そしてiOSユーザー向けにはApple Payも利用できます。

期待されないかもしれない、いくつかの際立った機能は次のとおりです。

  1. 約40製品、90種類の仕上げに対応した3Dモデルが利用可能
  2. 拡張現実(AR)により、ユーザーは照明や蛇口が自宅でどのように見えるかを98%のサイズ精度で確認できます。Build.comのReact Nativeアプリは、Apple App StoreのARショッピングで特集されています!ARは現在、AndroidとiOSの両方で利用可能です!
  3. 共同プロジェクト管理機能により、人々がプロジェクトのさまざまな段階ごとに買い物リストを作成し、選定について協力できます。

私たちは、ARによる没入型ショッピングの次の段階を含め、アプリ体験を向上させ続ける多くの新しくエキサイティングな機能に取り組んでいます。

開発ワークフロー

Build.comでは、各開発者が自分に最適なツールを選択できます。

  • IDEには、Atom、IntelliJ、VS Code、Sublime、Eclipseなどがあります。
  • 単体テストについては、開発者は新しいコンポーネントに対してJestの単体テストを作成する責任があり、私たちはjest-coverage-ratchetを使用してアプリの古い部分のカバレッジを増やす作業に取り組んでいます。
  • ベータ版とリリース候補のビルドにはJenkinsを使用しています。このプロセスは私たちにとってうまく機能していますが、リリースノートやその他の成果物を作成するには依然としてかなりの作業が必要です。
  • 結合テストには、デスクトップ、モバイル、Webにまたがって作業するテスターの共有プールが含まれています。私たちの自動化エンジニアは、JavaとAppiumを使用して自動化された結合テストスイートを構築しています。
  • ワークフローの他の部分には、詳細なeslint設定、テストに必要なプロパティを強制するカスタムルール、問題のある変更をブロックするpre-pushフックなどがあります。

アプリで使用されているライブラリ

Build.comアプリは、Redux、Moment、Numeral、Enzyme、そして多数のReact Nativeブリッジモジュールを含む、多くの一般的なオープンソースライブラリに依存しています。また、多くのフォークされたオープンソースライブラリも使用しています。これは、それらが放棄されたか、カスタム機能が必要だったためです。ざっと数えると、約115のJavaScriptおよびネイティブの依存関係があります。未使用のライブラリを削除するツールを検討したいと考えています。

私たちは現在、TypeScriptによる静的型付けの追加を進めており、オプショナルチェイニングも検討しています。これらの機能は、私たちがまだ目にしているいくつかの種類のバグを解決するのに役立つ可能性があります。

  • データが間違った型である
  • オブジェクトが期待した内容を含んでいないためにデータが未定義である

オープンソースへの貢献

私たちはオープンソースに大きく依存しているため、私たちのチームはコミュニティに貢献することにコミットしています。Build.comは、チームが構築したライブラリをオープンソース化することを許可し、私たちが使用しているライブラリに貢献することを奨励しています。

私たちは、いくつかのReact Nativeライブラリをリリースし、維持してきました。

  • react-native-polyfill
  • react-native-simple-store
  • react-native-contact-picker

私たちは、ReactとReact Native、react-native-schemes-managerreact-native-swipeablereact-native-galleryreact-native-view-transformerreact-native-navigationなど、多くのライブラリに貢献してきました。

私たちの歩み

過去数年間で、React Nativeとそのエコシステムは大きく成長しました。初期の頃は、React Nativeのバージョンが更新されるたびに、いくつかのバグが修正される一方で、さらにいくつかのバグが導入されるように見えました。例えば、リモートJSデバッグはAndroidで数か月間機能しませんでした。幸いなことに、2017年にははるかに安定しました。

私たちの大きな繰り返しの課題の1つは、ナビゲーションライブラリでした。長い間、Expoのex-navライブラリを使用していました。それは私たちにとってうまくいきましたが、最終的に非推奨になりました。しかし、当時は機能開発が盛んだったため、ナビゲーションライブラリを変更する時間を取ることはできませんでした。そのため、ライブラリをフォークして、React 16とiPhone Xをサポートするようにパッチを当てる必要がありました。最終的に、react-native-navigationに移行することができ、これが今後もサポートされ続けることを願っています。

ブリッジモジュール

もう一つの大きな課題はブリッジモジュールでした。最初に始めたとき、多くの重要なブリッジが不足していました。私たちのアプリでAndroidの連絡先ピッカーにアクセスする必要があったため、私のチームメイトの一人がreact-native-contact-pickerを作成しました。また、React Native内の変更によって壊れた多くのブリッジも見てきました。たとえば、React Native v40に破壊的変更があり、アプリをアップグレードしたとき、まだ更新されていなかった3つか4つのライブラリを修正するためにPRを提出しなければなりませんでした。

今後について

React Nativeが成長し続ける中で、私たちのコミュニティへのウィッシュリストは次のとおりです。

  • ナビゲーションライブラリを安定させ、改善する
  • React Nativeエコシステム内のライブラリのサポートを維持する
  • プロジェクトにネイティブライブラリとブリッジモジュールを追加する体験を改善する

React Nativeコミュニティの企業や個人は、私たちが皆使用するツールを改善するために、時間と労力を喜んで提供してくれました。もしあなたがオープンソースに関わったことがないなら、あなたが使用するいくつかのライブラリのコードやドキュメントの改善を検討することをお勧めします。始めるのに役立つ記事はたくさんありますし、思っているよりもずっと簡単かもしれません!

React Native用の<InputAccessoryView>の構築

2018年3月22日 ·7分で読めます
Peter Argany
Facebook ソフトウェアエンジニア

動機

3年前、React Nativeからinput accessory viewをサポートするためのGitHub issueが立てられました。

長年にわたり、この問題に関して数え切れないほどの「+1」やさまざまな回避策がありましたが、今日まで RN に具体的な変更はありませんでした。iOS から始まり、ネイティブの入力アクセサリビューにアクセスするための API を公開し、その構築方法を共有できることを嬉しく思います。

背景

入力アクセサリビューとは正確には何でしょうか? Apple の開発者向けドキュメントを読むと、レシーバーが最初のレスポンダーになったときに、システムキーボードの上部に固定できるカスタムビューであることがわかります。UIResponder を継承するものはすべて、.inputAccessoryView プロパティを読み書き可能として再宣言し、ここにカスタムビューを管理できます。レスポンダーインフラストラクチャはビューをマウントし、システムキーボードと同期を保ちます。ドラッグやタップなど、キーボードを閉じるジェスチャーは、フレームワークレベルで入力アクセサリビューに適用されます。これにより、iMessage や WhatsApp のようなトップティアのメッセージングアプリに不可欠な機能である、インタラクティブなキーボード閉鎖を備えたコンテンツを構築できます。

キーボードの上部にビューを固定する一般的なユースケースは2つあります。1つ目は、Facebookの投稿作成画面の背景ピッカーのようなキーボードツールバーを作成することです。

このシナリオでは、キーボードはテキスト入力フィールドにフォーカスされており、入力アクセサリビューは追加のキーボード機能を提供するために使用されます。この機能は、入力フィールドの種類によって異なります。マッピングアプリケーションでは住所の候補、テキストエディタではリッチテキスト書式設定ツールになる可能性があります。


このシナリオで <InputAccessoryView> を所有する Objective-C UIResponder は明確であるべきです。<TextInput> が最初のレスポンダーになり、内部的には UITextView または UITextField のインスタンスになります。

2つ目の一般的なシナリオは、スティッキーテキスト入力(追従するテキスト入力欄)です。

ここでは、テキスト入力自体がinput accessory viewの一部になっています。これはメッセージングアプリケーションでよく使用され、過去のメッセージのスレッドをスクロールしながらメッセージを作成できます。


この例で <InputAccessoryView> を所有するのは誰ですか? UITextView または UITextField が再び所有できますか? テキスト入力は入力アクセサリビューの内部にあります。これは循環依存のように聞こえます。この問題を解決すること自体が、別のブログ記事になります。ネタバレ:所有者は汎用的な UIView サブクラスであり、我々は手動で becomeFirstResponder を呼び出すように指示します。

API 設計

これで<InputAccessoryView>が何であるか、そしてそれをどのように使いたいかがわかりました。次のステップは、両方のユースケースにとって意味があり、<TextInput>のような既存のReact Nativeコンポーネントとうまく機能するAPIを設計することです。

キーボードツールバーについては、考慮したい点がいくつかあります。

  1. 任意の汎用的なReact Nativeのビュー階層を<InputAccessoryView>にホイスティング(引き上げ)できるようにしたい。
  2. この汎用的で分離されたビュー階層が、タッチイベントを受け付け、アプリケーションの状態を操作できるようにしたい。
  3. 特定の<TextInput><InputAccessoryView>をリンクさせたい。
  4. コードを複製することなく、複数のテキスト入力で<InputAccessoryView>を共有できるようにしたい。

React ポータルに似た概念を使用して #1 を実現できます。この設計では、React Native ビューをレスポンダーインフラストラクチャによって管理される UIView 階層にポータルします。React Native ビューは UIViews としてレンダリングされるため、これは実際には非常に簡単です。単にオーバーライドするだけです。

- (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)atIndex

そして、すべてのサブビューを新しい UIView 階層にパイプします。#2 の場合、<InputAccessoryView> 用に新しい RCTTouchHandler をセットアップします。状態の更新は、通常のイベントコールバックを使用して実現されます。#3 と #4 の場合、<TextInput> コンポーネントの作成中に、nativeID フィールドを使用して、ネイティブコードでアクセサリビューの UIView 階層を見つけます。この関数は、基になるネイティブテキスト入力の .inputAccessoryView プロパティを使用します。これにより、ObjC 実装で <InputAccessoryView><TextInput> に効果的にリンクされます。

スティッキーテキスト入力(シナリオ2)をサポートすると、さらにいくつかの制約が追加されます。この設計では、入力アクセサリビューに子としてテキスト入力があるため、nativeID を介したリンクはオプションではありません。代わりに、汎用的なオフスクリーン UIView.inputAccessoryView をネイティブの <InputAccessoryView> 階層に設定します。この汎用的な UIView に手動で最初のレスポンダーになるように指示することで、階層はレスポンダーインフラストラクチャによってマウントされます。この概念は、前述のブログ記事で詳しく説明されています。

落とし穴

もちろん、このAPIを構築する過程ですべてが順風満帆だったわけではありません。ここでは、私たちが遭遇したいくつかの落とし穴と、それらをどのように修正したかを紹介します。

この API を構築するための最初のアイデアには、UIKeyboardWill(Show/Hide/ChangeFrame) イベントの NSNotificationCenter をリッスンすることが含まれていました。このパターンは、いくつかのオープンソースライブラリや、Facebook アプリの一部で内部的に使用されています。残念ながら、スワイプ時に <InputAccessoryView> のフレームを更新するために UIKeyboardDidChangeFrame イベントが間に合いませんでした。また、キーボードの高さの変更もこれらのイベントでは捕捉されません。これにより、次のようなバグが発生します。

iPhone X では、テキストキーボードと絵文字キーボードの高さが異なります。キーボードイベントを使用してテキスト入力フレームを操作するほとんどのアプリケーションは、上記のバグを修正する必要がありました。私たちの解決策は、.inputAccessoryView プロパティを使用することにコミットすることでした。これは、レスポンダーインフラストラクチャがこのようなフレームの更新を処理することを意味します。


もう一つの厄介なバグは、iPhone X のホームピルを避けることでした。「Apple はこのためだけに safeAreaLayoutGuide を開発したのだから、これは些細なことだ!」とあなたは考えているかもしれません。私たちも同様に素朴でした。最初の問題は、ネイティブの <InputAccessoryView> 実装には、表示される直前までアンカーするウィンドウがないことです。それは問題ありません。-(BOOL)becomeFirstResponder をオーバーライドし、そこでレイアウト制約を強制できます。これらの制約に従うとアクセサリビューが上に移動しますが、別のバグが発生します。

入力アクセサリビューはホームピルを正常に回避しますが、今度は安全でない領域の後ろのコンテンツが表示されます。解決策は、この レーダーにあります。ネイティブの <InputAccessoryView> 階層を safeAreaLayoutGuide 制約に準拠しないコンテナでラップしました。ネイティブコンテナは安全でない領域のコンテンツをカバーし、<InputAccessoryView> は安全な領域の境界内に留まります。


使用例

以下は、<TextInput>の状態をリセットするためのキーボードツールバーボタンを構築する例です。

class TextInputAccessoryViewExample extends React.Component<
{},
*,
> {
constructor(props) {
super(props);
this.state = {text: 'Placeholder Text'};
}

render() {
const inputAccessoryViewID = 'inputAccessoryView1';
return (
<View>
<TextInput
style={styles.default}
inputAccessoryViewID={inputAccessoryViewID}
onChangeText={text => this.setState({text})}
value={this.state.text}
/>
<InputAccessoryView nativeID={inputAccessoryViewID}>
<View style={{backgroundColor: 'white'}}>
<Button
onPress={() =>
this.setState({text: 'Placeholder Text'})
}
title="Reset Text"
/>
</View>
</InputAccessoryView>
</View>
);
}
}

スティッキーテキスト入力の別の例はリポジトリにあります

いつ利用できるようになりますか?

この機能実装の完全なコミットはこちらです。<InputAccessoryView> は、今後の v0.55.0 リリースで利用可能になります。

ハッピーキーボーディング :)

React NativeでAWSを使用する

·10分で読めます
Richard Threlkeld
AWS Mobile シニアテクニカルプロダクトマネージャー

AWSは、クラウドサービスのプロバイダーとして、テクノロジー業界でよく知られています。これには、コンピューティング、ストレージ、データベース技術、およびフルマネージドのサーバーレス製品が含まれます。AWSモバイルチームは、クラウドに接続されたモバイルおよびウェブアプリケーションを、より安全で、スケーラブルで、開発およびデプロイしやすくするために、お客様やJavaScriptエコシステムのメンバーと密接に協力してきました。私たちは完全なスターターキットから始めましたが、最近のいくつかの開発があります。

このブログ記事では、ReactおよびReact Native開発者にとって興味深いことについて説明します。

  • AWS Amplify、クラウドサービスを使用するJavaScriptアプリケーション向けの宣言型ライブラリ
  • AWS AppSync、オフラインおよびリアルタイム機能を備えたフルマネージドGraphQLサービス

AWS Amplify

React Nativeアプリケーションは、Create React Native AppやExpoのようなツールを使って非常に簡単にブートストラップできます。しかし、ユースケースをインフラストラクチャサービスに合わせようとすると、それらをクラウドに接続するのは難しい場合があります。たとえば、React Nativeアプリで写真をアップロードする必要があるかもしれません。これらはユーザーごとに保護されるべきでしょうか?それはおそらく、何らかの登録またはサインインプロセスが必要であることを意味します。独自のユーザーディレクトリが必要ですか、それともソーシャルメディアプロバイダーを使用していますか?おそらく、アプリはユーザーがログインした後、カスタムビジネスロジックでAPIを呼び出す必要もあります。

JavaScript開発者がこれらの問題を解決するのを支援するために、AWS Amplifyというライブラリをリリースしました。設計は、AWS固有の実装ではなく、タスクの「カテゴリ」に分割されています。たとえば、ユーザーが登録、ログイン、そしてプライベート写真をアップロードできるようにしたい場合、単にAuthStorageカテゴリをアプリケーションに組み込むだけです。

import { Auth } from 'aws-amplify';

Auth.signIn(username, password)
.then(user => console.log(user))
.catch(err => console.log(err));

Auth.confirmSignIn(user, code)
.then(data => console.log(data))
.catch(err => console.log(err));

上記のコードでは、Amplifyが多要素認証(MFA)コードをメールまたはSMSで使用するなど、一般的なタスクをどのように支援するかの例を見ることができます。現在サポートされているカテゴリは次のとおりです。

  • Auth: 認証情報の自動化を提供します。既成の実装は、署名にAWS認証情報を使用し、Amazon CognitoからOIDC JWTトークンを使用します。MFA機能などの一般的な機能がサポートされています。
  • Analytics: 1行のコードで、認証済みまたは未認証のユーザーのトラッキングをAmazon Pinpointで取得できます。必要に応じて、カスタムメトリクスまたは属性のためにこれを拡張できます。
  • API: AWS Signature Version 4を活用して、RESTful APIとの安全な対話を提供します。APIモジュールは、Amazon API Gatewayを使用したサーバーレスインフラストラクチャに最適です。
  • Storage: Amazon S3でのコンテンツのアップロード、ダウンロード、リスト表示を簡素化するコマンドです。データは、ユーザーごとに公開またはプライベートコンテンツに簡単にグループ化できます。
  • キャッシング (Caching): ウェブアプリとReact Native全体で、実装固有の永続性を使用するLRUキャッシュインターフェースです。
  • i18nとロギング (i18n and Logging): 国際化とローカライズ機能、およびデバッグとロギング機能を提供します。

Amplifyの優れた点の1つは、特定のプログラミング環境向けに「ベストプラクティス」が設計に組み込まれていることです。たとえば、お客様やReact Native開発者との連携でわかったことの1つは、開発中に物事を迅速に機能させるために取られた近道が、本番スタックにまで及んでしまうことです。これらはスケーラビリティやセキュリティを損なう可能性があり、インフラストラクチャの再設計やコードのリファクタリングを強制する可能性があります。

開発者がこれを回避するのをどのように支援するかの一例は、AWS Lambdaによるサーバーレスリファレンスアーキテクチャです。これらは、バックエンドを構築する際にAmazon API GatewayとAWS Lambdaを一緒に使用するためのベストプラクティスを示しています。このパターンはAmplifyのAPIカテゴリにエンコードされています。このパターンを使用して、いくつかの異なるRESTエンドポイントと対話し、カスタムビジネスロジックのためにヘッダーをLambda関数にすべて渡すことができます。また、これらの機能を備えた新規または既存のReact NativeプロジェクトをブートストラップするためのAWS Mobile CLIもリリースしました。始めるには、npm経由でインストールし、構成プロンプトに従うだけです。

npm install --global awsmobile-cli
awsmobile configure

モバイルエコシステムに特化した、エンコードされたベストプラクティスのもう1つの例は、パスワードセキュリティです。デフォルトのAuthカテゴリの実装では、ユーザー登録とサインインにAmazon Cognitoユーザープールを利用しています。このサービスは、認証試行中にユーザーを保護する方法としてSecure Remote Passwordプロトコルを実装しています。もしプロトコルの数学的な部分を読みたい場合、Groupを生成するために原始根上でパスワード検証を計算する際に、大きな素数を使用する必要があることに気づくでしょう。React Native環境では、JITが無効になっています。これにより、このようなセキュリティ操作におけるBigInteger計算のパフォーマンスが低下します。この問題を解決するため、プロジェクト内でリンクできるAndroidおよびiOSのネイティブブリッジをリリースしました。

npm install --save aws-amplify-react-native
react-native link amazon-cognito-identity-js

Expoチームが最新のSDKにこれを含めてくれたことにも興奮しています。これにより、イジェクトせずにAmplifyを使用できます。

最後に、React Native(およびReact)開発に特化して、Amplifyには、アプリへのサインアップやサインインなどの機能を簡単にラップするための高階コンポーネント(HOC)が含まれています。

import Amplify, { withAuthenticator } from 'aws-amplify-react-native';
import aws_exports from './aws-exports';

Amplify.configure(aws_exports);

class App extends React.Component {
...
}

export default withAuthenticator(App);

基盤となるコンポーネントも<Authenticator />として提供されており、UIを完全にカスタマイズできます。また、ユーザーのサインイン状態、MFA確認待ちの状態など、ユーザーの状態管理に関するいくつかのプロパティや、状態変化時に実行できるコールバックも提供されます。

同様に、さまざまなユースケースで使用できる一般的なReactコンポーネントが見つかります。これらは、たとえば、StorageモジュールでAmazon S3からすべてのプライベート画像を表示するなど、ニーズに合わせてカスタマイズできます。

<S3Album
level="private"
path={path}
filter={(item) => /jpg/i.test(item.path)}/>

前述のとおり、公開またはプライベートストレージオプションを使用して、多くのコンポーネント機能をprops経由で制御できます。ユーザーが特定のUIコンポーネントと対話したときに、分析を自動的に収集する機能さえあります。

return <S3Album track/>

AWS Amplifyは、グローバルな初期化ルーチンまたはカテゴリレベルでの初期化を備えた、設定よりも規約重視の開発スタイルを好みます。開始する最も簡単な方法は、aws-exportsファイルを使用することです。ただし、開発者は既存のリソースと独立してライブラリを使用することもできます。

哲学を深く掘り下げて完全なデモを見るには、AWS re:Inventのビデオをご覧ください。

AWS AppSync

AWS Amplifyのローンチ直後、AWS AppSyncもリリースしました。これは、オフライン機能とリアルタイム機能の両方を備えたフルマネージドのGraphQLサービスです。GraphQLはさまざまなクライアントプログラミング言語(ネイティブのAndroidやiOSを含む)で使用できますが、React Native開発者の間で非常に人気があります。これは、データモデルが一方向データフローとコンポーネント階層にうまく適合するためです。

AWS AppSyncを使用すると、独自のAWSアカウントのリソースに接続できるため、データの所有権と制御はユーザーにあります。これはデータソースを使用して行われ、サービスはAmazon DynamoDBAmazon Elasticsearch、およびAWS Lambdaをサポートしています。これにより、単一のGraphQL APIでスキーマとして機能(NoSQLや全文検索など)を組み合わせることができます。これにより、データソースを自由に組み合わせることができます。AppSyncサービスはスキーマからプロビジョニングすることもできるため、AWSサービスに慣れていない場合でも、GraphQL SDLを記述してボタンをクリックするだけで、自動的に起動して実行できます。

AWS AppSyncのリアルタイム機能は、よく知られたイベントベースのパターンを持つGraphQLサブスクリプションを通じて制御されます。AWS AppSyncのサブスクリプションは、GraphQLディレクティブを持つスキーマで制御され、スキーマは任意のデータソースを使用できるため、Amazon DynamoDBとAmazon Elasticsearch Serviceでのデータベース操作、またはAWS Lambdaを使用したインフラストラクチャの他の部分から通知をトリガーできます。

AWS Amplifyと似た方法で、AWS AppSyncを使用してGraphQL APIのエンタープライズセキュリティ機能を使用できます。このサービスを使用すると、APIキーですばやく開始できます。ただし、本番環境に移行する際には、AWS Identity and Access Management (IAM) またはAmazon CognitoユーザープールからのOIDCトークンを使用するように移行できます。型に対するポリシーを使用して、リゾルバーレベルでアクセスを制御できます。実行時にきめ細かなアクセス制御チェックのために論理チェックを使用することもできます。たとえば、ユーザーが特定のデータベースリソースの所有者であるかどうかを検出するなどです。また、リゾルバーの実行または個々のデータベースレコードへのアクセスに対するグループメンバーシップのチェックに関する機能もあります。

React Native開発者がこれらのテクノロジーについてさらに学ぶのを支援するために、AWS AppSyncコンソールのホームページで起動できる組み込みのGraphQLサンプルスキーマがあります。このサンプルは、GraphQLスキーマをデプロイし、データベーステーブルをプロビジョニングし、クエリ、ミューテーション、およびサブスクリプションを自動的に接続します。また、この組み込みスキーマを活用するAWS AppSync用の動作するReact Nativeの例(およびReactの例)もあり、クライアントとクラウドの両方のコンポーネントを数分で実行できます。

AWSAppSyncClientを使用すると、Apollo Clientにプラグインするため、簡単に開始できます。AWSAppSyncClientは、GraphQL APIのセキュリティと署名、オフライン機能、およびサブスクリプションのハンドシェイクとネゴシエーションプロセスを処理します。

import AWSAppSyncClient from "aws-appsync";
import { Rehydrated } from 'aws-appsync-react';
import { AUTH_TYPE } from "aws-appsync/lib/link/auth-link";

const client = new AWSAppSyncClient({
url: awsconfig.graphqlEndpoint,
region: awsconfig.region,
auth: {type: AUTH_TYPE.API_KEY, apiKey: awsconfig.apiKey}
});

AppSyncコンソールは、GraphQLエンドポイント、AWSリージョン、APIキーを含む設定ファイルをダウンロード用に提供します。その後、React Apolloでクライアントを使用できます。

const WithProvider = () => (
<ApolloProvider client={client}>
<Rehydrated>
<App />
</Rehydrated>
</ApolloProvider>
);

この時点で、標準のGraphQLクエリを使用できます。

query ListEvents {
listEvents{
items{
__typename
id
name
where
when
description
comments{
__typename
items{
__typename
eventId
commentId
content
createdAt
}
nextToken
}
}
}
}

上記の例は、AppSyncによってプロビジョニングされたサンプルアプリのスキーマを使用したクエリを示しています。DynamoDBとの対話だけでなく、データ(暗号化されたトークンを含む)のページネーションや、EventsComments間のタイプリレーションも含まれています。アプリはAWSAppSyncClientで構成されているため、データは自動的にオフラインで永続化され、デバイスが再接続すると同期されます。

このビデオで、この背後にあるクライアントテクノロジーの深掘りおよびReact Nativeのデモをご覧いただけます。

フィードバック

ライブラリの背後にあるチームは、これらのライブラリとサービスがどのように機能しているかをお聞きすることを熱望しています。また、クラウドサービスでのReactおよびReact Native開発をより簡単にするために、他に何ができるかについても知りたいと思っています。AWS AmplifyまたはAWS AppSyncについて、GitHubでAWSモバイルチームにお問い合わせください。

React NativeでTwitterのアプリ起動アニメーションを実装する

·12分で読めます
Eli White
Eli White
ソフトウェアエンジニア @ Meta

TwitterのiOSアプリには、私がとても気に入っているローディングアニメーションがあります。

アプリの準備が整うと、Twitterのロゴが楽しく拡大し、アプリが現れます。

このローディングアニメーションをReact Nativeで再現する方法を考え出したいと思いました。


それをどのように作るかを理解するためには、まずローディングアニメーションの異なる部分を理解する必要がありました。その微妙な違いを見る一番簡単な方法は、スロー再生することです。

これを構築するためには、いくつか主要な要素を理解する必要があります。

  1. 鳥を拡大する。
  2. 鳥が大きくなるにつれて、その下のアプリが表示される
  3. 最後にアプリをわずかに縮小する

このアニメーションの作り方を理解するのに、かなりの時間がかかりました。

当初、私は、青い背景とTwitterの鳥がアプリの「上」のレイヤーになっていて、鳥が大きくなるにつれて透明になり、下のアプリが現れるという「間違った」仮定から始めました。このアプローチは、Twitterの鳥が透明になると青いレイヤーが見えてしまい、下のアプリが見えないため機能しません!

幸運なことに、読者の皆さんは私と同じようなフラストレーションを経験する必要はありません。この素敵なチュートリアルで、良いところだけをすぐに学べます!


正しい方法

コードに入る前に、これをどのように分解するかを理解することが重要です。この効果を視覚化するために、CodePenで再現しました(数段落後に埋め込まれています)。これにより、異なるレイヤーをインタラクティブに確認できます。

このエフェクトには主に3つのレイヤーがあります。1つ目は青い背景レイヤーです。これはアプリの上に表示されているように見えますが、実際には背面にあります。

次に、真っ白なレイヤーがあります。そして最後に、一番手前に私たちのアプリがあります。


このアニメーションの主な秘訣は、Twitterロゴをmaskとして使用し、アプリと白いレイヤーの両方をマスクすることです。マスキングの詳細については深く掘り下げません。それについてはたくさんリソースオンラインにあります。

この文脈でのマスキングの基本は、マスクの不透明なピクセルがマスキング対象のコンテンツを表示し、透明なピクセルがマスキング対象のコンテンツを隠す画像を持つことです。

私たちはTwitterのロゴをマスクとして使用し、真っ白なレイヤーとアプリレイヤーの2つのレイヤーをマスキングします。

アプリを表示させるために、マスクを画面全体より大きくなるまで拡大します。

マスクが拡大する間、アプリレイヤーの不透明度をフェードインさせ、アプリを表示し、その背後にあるソリッドな白いレイヤーを隠します。効果を完成させるために、アプリレイヤーをスケール > 1 で開始し、アニメーションの終了時に1まで縮小させます。その後、二度と見られることのない非アプリレイヤーを非表示にします。

百聞は一見に如かずと言いますが、インタラクティブな視覚化はどれほどの価値があるでしょうか?「Next Step」ボタンでアニメーションをクリックして進んでみてください。レイヤーを表示すると、側面からの視点が得られます。グリッドは透明なレイヤーを視覚化するのに役立ちます。

いよいよReact Nativeについて

さてと。何を構築するのか、そしてアニメーションがどのように機能するのかがわかったので、コードに取り掛かりましょう――皆さんが本当にここにいる理由です。

このパズルの主要なピースは、React NativeのコアコンポーネントであるMaskedViewIOSです。

import {MaskedViewIOS} from 'react-native';

<MaskedViewIOS maskElement={<Text>Basic Mask</Text>}>
<View style={{backgroundColor: 'blue'}} />
</MaskedViewIOS>;

MaskedViewIOSmaskElementchildrenというプロパティを受け取ります。子要素はmaskElementによってマスクされます。マスクは画像である必要はなく、任意のビューで構いません。上記の例の動作は、青いビューがレンダリングされますが、そのビューはmaskElementの「Basic Mask」という文字がある部分でのみ表示されます。これで複雑な青いテキストができました。

私たちがやりたいことは、青いレイヤーをレンダリングし、その上にTwitterロゴでマスクされたアプリと白いレイヤーをレンダリングすることです。

{
fullScreenBlueLayer;
}
<MaskedViewIOS
style={{flex: 1}}
maskElement={
<View style={styles.centeredFullScreen}>
<Image source={twitterLogo} />
</View>
}>
{fullScreenWhiteLayer}
<View style={{flex: 1}}>
<MyApp />
</View>
</MaskedViewIOS>;

これにより、以下に見られるレイヤーが得られます。

さて、アニメーション部分について

これを機能させるために必要なすべてのピースが揃いました。次のステップはそれらをアニメーション化することです。このアニメーションを良い感じにするために、React NativeのAnimated APIを活用します。

Animatedを使うと、JavaScriptでアニメーションを宣言的に定義できます。デフォルトでは、これらのアニメーションはJavaScriptで実行され、毎フレームごとにネイティブレイヤーにどのような変更を行うかを指示します。JavaScriptは毎フレームアニメーションを更新しようとしますが、十分な速さで実行できず、フレーム落ち(カクつき)が発生する可能性があります。これは望ましくありません!

Animatedには、このカクつきなしでアニメーションを実現するための特別な動作があります。AnimatedにはuseNativeDriverというフラグがあり、アニメーションの開始時にJavaScriptからネイティブにアニメーション定義を送信します。これにより、ネイティブ側が毎フレームJavaScriptを行き来することなく、アニメーションの更新を処理できます。useNativeDriverの欠点は、更新できるプロパティがtransformopacityにほぼ限定されることです。背景色のようなものをuseNativeDriverでアニメーションさせることはできません(少なくともまだ)。今後、徐々に追加していく予定ですし、もちろんプロジェクトで必要なプロパティがあれば、いつでもプルリクエストを送信して、コミュニティ全体に貢献できます😀。

このアニメーションを滑らかにしたいので、これらの制約の中で作業します。useNativeDriverが内部でどのように機能するかをより詳しく知りたい場合は、それを発表したブログ記事をご覧ください。

アニメーションを分解する

私たちのアニメーションには4つの構成要素があります。

  1. 鳥を拡大し、アプリと真っ白なレイヤーを表示する
  2. アプリをフェードインさせる
  3. アプリを縮小する
  4. 完了したら、白いレイヤーと青いレイヤーを非表示にする

Animatedでは、アニメーションを定義する主な方法が2つあります。1つ目はAnimated.timingを使用する方法で、アニメーションの実行時間と、動きを滑らかにするイージングカーブを正確に指定できます。もう1つの方法は、Animated.springなどの物理ベースのAPIを使用する方法です。Animated.springでは、バネの摩擦や張力といったパラメーターを指定し、物理演算によってアニメーションを実行させます。

私たちは、互いに密接に関連する複数のアニメーションを同時に実行したいと考えています。例えば、マスクが半分表示されている間にアプリをフェードインさせたいのです。これらのアニメーションは密接に関連しているため、単一のAnimated.ValueAnimated.timingを使用します。

Animated.Valueは、Animatedがアニメーションの状態を知るために使用するネイティブ値のラッパーです。通常、完全なアニメーションに対してはこれを1つだけ持つのが望ましいです。Animatedを使用するほとんどのコンポーネントは、この値をstateに保存します。

私はこのアニメーションを、完全なアニメーションの進行に沿って異なる時点で発生するステップとして考えているので、Animated.Valueを0(0%完了を表す)から始め、値を100(100%完了を表す)で終了させます。

コンポーネントの初期stateは次のようになります。

state = {
loadingProgress: new Animated.Value(0),
};

アニメーションを開始する準備ができたら、Animatedにこの値を100にアニメーションするように指示します。

Animated.timing(this.state.loadingProgress, {
toValue: 100,
duration: 1000,
useNativeDriver: true, // This is important!
}).start();

次に、アニメーションのさまざまな部分と、全体のアニメーションの異なる段階でそれらが持つべき値の概算を把握しようとしました。以下は、アニメーションのさまざまな部分と、時間の経過とともにそれらの値が異なる時点でどうあるべきかを示す表です。

Twitterの鳥のマスクはスケール1で始まり、サイズが急増する前に小さくなります。したがって、アニメーションの10%の時点で、スケール値は0.8になり、最後にスケール70まで急増します。正直なところ、70という数字はかなり任意に選んだもので、鳥が画面全体を完全に明らかにするのに十分な大きさが必要で、60では不十分でした😀。ただし、この部分で興味深いのは、数字が大きいほど、同じ時間でそこに到達しなければならないため、成長が速く見えるということです。この数字は、このロゴで見栄えがするように試行錯誤が必要でした。異なるサイズのロゴ/デバイスでは、画面全体が明らかになるように、この最終スケールが異なる必要があります。

アプリはしばらく不透明なままで、少なくともTwitterロゴが小さくなる間はそうです。公式のアニメーションに基づいて、鳥が拡大している途中で表示を開始し、かなり早く完全に表示したいと考えています。したがって、15%の時点で表示を開始し、全体のアニメーションの30%の時点で完全に表示されます。

アプリのスケールは1.1から始まり、アニメーションの終わりまでに通常のスケールに縮小します。

そして、いよいよコードです。

上記で基本的に行ったのは、アニメーションの進行率から個々の部分の値へのマッピングです。これをAnimatedで.interpolateを使って行います。this.state.loadingProgressに基づいて補間された値を使用し、アニメーションの各部分に対して3つの異なるスタイルオブジェクトを作成します。

const loadingProgress = this.state.loadingProgress;

const opacityClearToVisible = {
opacity: loadingProgress.interpolate({
inputRange: [0, 15, 30],
outputRange: [0, 0, 1],
extrapolate: 'clamp',
// clamp means when the input is 30-100, output should stay at 1
}),
};

const imageScale = {
transform: [
{
scale: loadingProgress.interpolate({
inputRange: [0, 10, 100],
outputRange: [1, 0.8, 70],
}),
},
],
};

const appScale = {
transform: [
{
scale: loadingProgress.interpolate({
inputRange: [0, 100],
outputRange: [1.1, 1],
}),
},
],
};

これらのスタイルオブジェクトができたので、以前の投稿で紹介したビューのスニペットをレンダリングするときにそれらを使用できます。Animated.Valueを使用するスタイルオブジェクトを使用できるのは、Animated.ViewAnimated.Text、およびAnimated.Imageだけであることに注意してください。

const fullScreenBlueLayer = (
<View style={styles.fullScreenBlueLayer} />
);
const fullScreenWhiteLayer = (
<View style={styles.fullScreenWhiteLayer} />
);

return (
<View style={styles.fullScreen}>
{fullScreenBlueLayer}
<MaskedViewIOS
style={{flex: 1}}
maskElement={
<View style={styles.centeredFullScreen}>
<Animated.Image
style={[styles.maskImageStyle, imageScale]}
source={twitterLogo}
/>
</View>
}>
{fullScreenWhiteLayer}
<Animated.View
style={[opacityClearToVisible, appScale, {flex: 1}]}>
{this.props.children}
</Animated.View>
</MaskedViewIOS>
</View>
);

やった!これでアニメーションの各部分が望み通りに見えるようになりました。あとは、二度と表示されない青と白のレイヤーをクリーンアップするだけです。

いつクリーンアップできるかを知るためには、アニメーションがいつ完了したかを知る必要があります。幸いなことに、Animated.timingを呼び出す場所で、.startはアニメーション完了時に実行されるオプションのコールバックを受け取ります。

Animated.timing(this.state.loadingProgress, {
toValue: 100,
duration: 1000,
useNativeDriver: true,
}).start(() => {
this.setState({
animationDone: true,
});
});

これで、アニメーションが完了したかどうかを知るための値がstateに入ったので、青と白のレイヤーを修正してそれを使用できます。

const fullScreenBlueLayer = this.state.animationDone ? null : (
<View style={[styles.fullScreenBlueLayer]} />
);
const fullScreenWhiteLayer = this.state.animationDone ? null : (
<View style={[styles.fullScreenWhiteLayer]} />
);

できました!これでアニメーションが機能し、アニメーションが完了したら不要なレイヤーをクリーンアップします。Twitterアプリのローディングアニメーションを構築しました!

でも待って、私の動かない!

心配しないでください、読者の皆さん。私も、ガイドがコードの一部しか提供せず、完成したソースコードをくれないときは嫌なものです。

このコンポーネントはnpmに公開されており、GitHubではreact-native-mask-loaderとして提供されています。お使いのスマートフォンで試すには、こちらでExpoで利用可能です。

さらに読む / 追加課題

  1. React Nativeのドキュメントを読んだ後、Animatedについてさらに学ぶにはこのgitbookが素晴らしいリソースです。
  2. 実際のTwitterアニメーションは、最後に近づくにつれてマスクの表示が速くなるようです。その動作によりよく一致するように、異なるイージング関数(またはspring!)を使用するようにローダーを修正してみてください。
  3. 現在のマスクの最終スケールはハードコードされており、タブレットではアプリ全体を表示できない可能性があります。画面サイズと画像サイズに基づいて最終スケールを計算することは、素晴らしいPRになるでしょう。

React Nativeマンスリー #6

·4分で読めます
Tomislav Tenodi
Speck 創設者

React Nativeの月例ミーティングは、今も盛況です!次回のセッションについては、この記事の最後のお知らせをぜひチェックしてください。

Expo

  • Devin AbbottHoussein Djirdeh による「Full Stack React Native」本のプレリリース、おめでとうございます!この本では、いくつかの小さなアプリを構築することで React Native を学ぶことができます。
  • ReasonML を簡単に試せるよう、reason-react-native-scripts の最初の(実験的な)バージョンをリリースしました。
  • Expo SDK 24 がリリースされました!これは React Native 0.51 を使用しており、多くの新機能と改善が含まれています。例えば、スタンドアロンアプリでの画像のバンドル(初回読み込み時のキャッシュが不要に!)、画像操作 API(切り抜き、サイズ変更、回転、反転)、顔検出 API、新しいリリースチャネル機能(特定のチャネルのアクティブなリリース設定とロールバック)、スタンドアロンアプリのビルドを追跡するウェブダッシュボード、OpenGL Android 実装と Android マルチタスカーに関する長年のバグの修正などです。
  • 今年1月から、React Navigation にさらに多くのリソースを割り当てています。React コンポーネントと Animated や react-native-gesture-handler のようなプリミティブだけで React Native ナビゲーションを構築することは可能であり、望ましいことだと強く信じており、計画しているいくつかの改善に非常に期待しています。コミュニティに貢献したい方は、react-native-mapsreact-native-svg をチェックしてみてください。どちらも助けを必要としています!

Infinite Red

Microsoft

  • コアとなる React Native Windows ブリッジを .NET Standard に移行するためのプルリクエストが開始され、これにより事実上 OS に依存しなくなります。これにより、他の多くの .NET Core プラットフォームが独自のスレッドモデル、JavaScript ランタイム、UIManagers (JavaScriptCore、Xamarin.Mac、Linux Gtk#、Samsung Tizen など) でブリッジを拡張できるようになることを期待しています。

Wix

  • Detox
    • E2Eテストをスケールさせるため、CIに費やす時間を最小限に抑えたいと考えており、Detoxの並列化サポートに取り組んでいます。
    • E2Eでのモックをより良くサポートするため、カスタムフレーバービルドを有効にするプルリクエストを提出しました。
  • DetoxInstruments
    • DetoxInstruments のキラー機能の開発は非常に困難な作業であることが判明しました。任意の時点での JavaScript バックトレースを取得するには、JS スレッドの一時停止をサポートするカスタム JSCore 実装が必要です。Wix アプリでプロファイラを内部テストしたところ、JS スレッドに関する興味深い洞察が得られました。
    • このプロジェクトはまだ一般利用には十分安定していませんが、活発に開発が進められており、近いうちに発表できることを願っています。
  • React Native Navigation
    • V2の開発ペースが大幅に上がりました。これまでは開発者1名が20%の時間で作業していましたが、現在では3名の開発者がフルタイムで取り組んでいます!
  • Androidのパフォーマンス
    • RN にバンドルされている古い JSCore を最新バージョン(WebKitGTK プロジェクトの先端、カスタム JIT 設定付き)に置き換えたところ、JS スレッドで 40% のパフォーマンス向上を達成しました。次は 64 ビット版のコンパイルです。この取り組みは Android 用 JSC ビルドスクリプトに基づいています。現在の状況はこちらで確認できます。

次のセッション

この会議の目的を、単一の特定のトピック(例:ナビゲーション、React Native モジュールの別リポジトリへの移動、ドキュメントなど)について議論するように変更することについて議論がありました。そうすることで、React Native コミュニティに最善の貢献ができると考えています。これは次の会議セッションで行われるかもしれません。トピックとして取り上げてほしい内容があれば、自由にツイートしてください。

React Nativeマンスリー #5

·4分で読めます
Tomislav Tenodi
Speck 創設者

React Nativeの月例ミーティングは続きます!各チームの取り組みを見てみましょう。

Callstack

  • 私たちはReact NativeのCIに取り組んできました。最も重要なこととして、TravisからCircleに移行し、React NativeのCIパイプラインを1つに統一しました。
  • 私たちは、参加者の皆さんと一緒にオープンソースプロジェクトに多くのプルリクエストを送信する「Hacktoberfest - React Native edition」を開催しました。
  • 私たちはHaulの開発を続けています。先月、webpack 3のサポートを含む2つの新しいリリースを公開しました。今後はCRNAExpoのサポートを追加し、より良いHMRに取り組む予定です。ロードマップはissueトラッカーで公開されています。改善点やフィードバックがあれば、ぜひお知らせください!

Expo

  • Expo SDK 22(React Native 0.49を使用)をリリースし、それに対応するCRNAを更新しました。
    • 改善されたスプラッシュスクリーンAPI、基本的なARKitサポート、「DeviceMotion」API、iOS11でのSFAuthenticationSessionサポート、その他が含まれています。
  • あなたのSnackで複数のJavaScriptファイルを持てるようになり、画像やその他のアセットをエディタにドラッグ&ドロップするだけでアップロードできるようになりました。
  • iPhone Xのサポートを追加するためにreact-navigationにコントリビュートしてください。
  • Expoで大規模なアプリケーションを構築する際の課題に注力しています。例えば、
    • ステージング、プロダクション、および任意のチャネルへのデプロイに対するファーストクラスのサポート。チャネルは、ロールバックと特定のチャネルのアクティブなリリースの設定をサポートします。早期テスターをご希望の場合は、@expo_ioまでお知らせください。
    • また、スタンドアロンアプリのビルドインフラを改善し、OTA(Over The Air)でのアセット更新機能を維持しつつ、スタンドアロンアプリのビルドに画像やその他の非コードアセットをバンドルするサポートを追加する作業にも取り組んでいます。

Facebook

  • RTLサポートの改善
    • 方向を意識したスタイルを多数導入しています。
      • Position
        • (left|right) → (start|end)
      • Margin
        • margin(Left|Right) → margin(Start|End)
      • Padding
        • padding(Left|Right) → padding(Start|End)
      • Border
        • borderTop(Left|Right)Radius → borderTop(Start|End)Radius
        • borderBottom(Left|Right)Radius → borderBottom(Start|End)Radius
        • border(Left|Right)Width → border(Start|End)Width
        • border(Left|Right)Color → border(Start|End)Color
    • RTLでは、position、margin、padding、borderスタイルにおいて「left」と「right」の意味が入れ替わっていました。数ヶ月以内にこの動作を削除し、「left」が常に「左」を、「right」が常に「右」を意味するようにします。この破壊的変更はフラグの下に隠されています。React NativeコンポーネントでI18nManager.swapLeftAndRightInRTL(false)を使用して、これらにオプトインしてください。
  • 内部のネイティブモジュールにFlowタイピングを施し、それを使用してJavaでインターフェースを、ObjCでプロトコルを生成し、ネイティブ実装がこれらを実装する必要があるように作業を進めています。このコード生成は、早ければ来年にはオープンソース化されることを願っています。

Infinite Red

  • React Nativeや他のプロジェクトを支援するための新しいOSSツールです。詳細はこちら
  • 新しいボイラープレートリリース(コードネーム:Bowser)のためにIgniteを刷新しています。

Shoutem

  • Shoutemでの開発フローを改善しています。アプリの作成から最初のカスタム画面までのプロセスを効率化し、非常に簡単にすることで、新しいReact Native開発者にとっての障壁を低くしたいと考えています。新しい機能をテストするためにいくつかのワークショップを準備しました。また、新しいフローをサポートするためにShoutem CLIを改善しました。
  • Shoutem UIはいくつかのコンポーネントの改善とバグ修正が行われました。また、最新のReact Nativeバージョンとの互換性も確認しました。
  • Shoutemプラットフォームはいくつかの notable なアップデートを受け、オープンソース拡張機能プロジェクトの一部として新しい統合が利用可能になりました。他の開発者によるShoutem拡張機能の活発な開発に大変興奮しています。私たちは積極的に連絡を取り、彼らの拡張機能についてアドバイスとガイダンスを提供しています。

次のセッション

次回のセッションは2017年12月6日水曜日に予定されています。会議の成果を改善する方法について何かご提案があれば、お気軽にTwitterで私に連絡してください。

React Nativeマンスリー #4

·3分で読めます
Mike Grabowski
Mike Grabowski
Callstack CTO兼共同創設者

React Nativeの月例ミーティングは続きます!各チームからの議事録はこちらです。

Callstack

  • React Native EUが終了しました。33カ国から300人以上の参加者がヴロツワフを訪れました。トークはYouTubeでご覧いただけます。
  • カンファレンス後、私たちは徐々にオープンソースのスケジュールに戻っています。特筆すべきは、既存のほとんどの問題を修正するreact-native-opentokの次期リリースに取り組んでいることです。

GeekyAnts

以下の取り組みにより、React Nativeを採用する開発者の参入障壁を下げようとしています。

  • React Native EUBuilderX.ioを発表しました。BuilderXはJavaScriptファイル(現時点ではReact Nativeのみをサポート)と直接連携し、美しく、読みやすく、編集可能なコードを生成するデザインツールです。
  • ReactNativeSeed.comを立ち上げました。これは、次のReact Nativeプロジェクト用のボイラープレートのセットを提供します。CRNAとプレーンなReact-Nativeをスタックとして、データ型にはTypeScript&Flow、状態管理にはMobX、Redux、mobx-state-treeを含むさまざまなオプションが用意されています。

Expo

  • まもなくSDK 21をリリースします。これにより、react-native 0.48.3のサポートが追加され、ビデオ録画、新しいスプラッシュスクリーンAPI、react-native-gesture-handlerのサポート、エラー処理の改善など、Expo SDKの多くのバグ修正/信頼性改善/新機能が追加されます。
  • react-native-gesture-handlerについて、Software MansionKrzysztof Magieraが引き続き開発を進めており、私たちは彼のテストと開発時間の一部を資金援助しています。SDK21でExpoにこれが統合されることで、Snackで簡単に試せるようになるので、皆さんがどのようなものを作り出すか楽しみです。
  • エラーログ/ハンドリングの改善について - ログの詳細(特に「問題2」)についてはこのExpoの内部PRの要点を、npm標準ライブラリモジュールのインポート失敗を処理する変更についてはこのコミットを参照してください。このようにReact Nativeのアップストリームでエラーメッセージを改善する機会はたくさんあり、私たちは今後もアップストリームのPRに取り組んでいきます。コミュニティの皆様にもご参加いただけると幸いです。
  • native.directoryは成長を続けており、GitHubリポジトリからプロジェクトを追加できます。
  • PennAppsHack The NorthHackMIT、そしてまもなくMHacksを含む北米各地のハッカソンを訪れてください。

Facebook

  • Android上の<Text>および<TextInput>コンポーネントの改善に取り組んでいます。(<TextInput>のネイティブ自動拡張、深くネストされた<Text>コンポーネントのレイアウト問題、より良いコード構造、パフォーマンス最適化)。
  • 私たちは引き続き、issueやプルリクエストのトリアージを手伝ってくれるコントリビューターを探しています。

Microsoft

  • CodePushのコード署名機能をリリースしました。React Native開発者は、CodePushでアプリケーションバンドルに署名できるようになりました。発表はこちらでご覧いただけます。
  • CodePushのMobile Centerへの統合完了に取り組んでいます。テストやクラッシュレポートの統合も検討中です。

次のセッション

次回のセッションは2017年10月10日水曜日に予定されています。今回がまだ4回目の会議でしたので、これらのメモがReact Nativeコミュニティにどのように役立っているかを知りたいです。会議の成果をどのように改善すべきかについてご提案があれば、お気軽にTwitterで私にご連絡ください

React Nativeマンスリー #3

·5分で読めます
Mike Grabowski
Mike Grabowski
Callstack CTO兼共同創設者

React Native 月次ミーティングは続いています!今月のミーティングは、ほとんどのチームがリリースで忙しかったため、少し短くなりました。来月は、ポーランドのヴロツワフで開催される React Native EU カンファレンスに参加します。チケットを手に入れて、会場でお会いしましょう!その間に、私たちのチームが何をしているか見てみましょう。

チーム

この3回目の会議には、5つのチームが参加しました

ノート

以下は各チームからの議事録です。

Callstack

  • 最近オープンソース化された react-native-material-palette。これは、画像から主要な色を抽出し、視覚的に魅力的なアプリを作成するのに役立ちます。現時点では Android のみですが、将来的には iOS のサポートを追加する予定です。
  • haul に HMR サポートとその他のクールな機能が追加されました!最新リリースをチェックしてください。
  • React Native EU 2017 が近づいています!来月は React Native とポーランドがテーマです!残りのチケットは こちら でお早めにお求めください。

Expo

  • Snack で npm パッケージをインストールするサポートをリリースしました。通常の Expo の制限が適用されます。つまり、Expo にすでに含まれていないカスタムネイティブ API に依存するパッケージは使用できません。また、Snack で複数のファイルをサポートし、アセットをアップロードする作業も行っています。SatyajitReact Native Europe で Snack について講演します。
  • カメラ、決済、安全なストレージ、磁力計、fsダウンロードの一時停止/再開、スプラッシュ/ローディング画面の改善を含むSDK20をリリースしました。
  • Krzysztofreact-native-gesture-handler の作業を続けています。ぜひ試して、以前 PanResponder やネイティブジェスチャー認識機能を使って構築したジェスチャーを再構築し、遭遇した問題をお知らせください。
  • JSCデバッグプロトコルを試したり、Cannyで多数の機能リクエストに対応しています。

Facebook

  • 先月、GitHub のイシュートラッカーの管理について議論し、プロジェクトの保守性を向上させるための改善を試みることを決定しました。
  • 現在、未解決のイシューの数は約 600 件で安定しており、しばらくその状態が続きそうです。先月、活動がない(過去 60 日間にコメントがないと定義)ため 690 件のイシューをクローズしました。その 690 件のイシューのうち、さまざまな理由(メンテナーが修正を提供すると約束した、またはコントリビューターがイシューをオープンにしておく強力な理由を提示した)で 58 件が再オープンされました。
  • 今後も、古くなったイシューの自動クローズを続ける予定です。トラッカーで開かれた影響力のあるすべてのイシューに対処できる状態になりたいと考えていますが、まだそこには至っていません。イシューをトリアージし、特に新しく作成されたプロジェクトに影響を与えるリグレッションや破壊的変更を導入するイシューを見逃さないように、メンテナーからのあらゆる助けが必要です。支援に関心のある方は、Facebook GitHub Bot を使用してイシューやプルリクエストをトリアージできます。新しいメンテナーガイドには、トリアージと GitHub Bot の使用に関する詳細情報が含まれています。イシュータスクフォースに自分自身を追加し、他の活発なコミュニティメンバーにも同じことをするよう奨励してください!

Microsoft

  • 新しい Skype アプリは、可能な限り多くのコードをプラットフォーム間で共有できるように、React Native をベースに構築されています。React Native ベースの Skype アプリは現在、Android および iOS のアプリストアで利用可能です。
  • React Native で Skype アプリを構築する際、遭遇するバグや不足している機能に対処するために、React Native にプルリクエストを送信しています。これまでに、約 70 件のプルリクエストがマージされました。
  • React Native のおかげで、Android と iOS の両方の Skype アプリを同じコードベースで動かすことができました。また、そのコードベースを Skype ウェブアプリにも活用したいと考えています。この目標を達成するために、React/React Native の上に薄いレイヤーを構築し、ReactXP としてオープンソース化しました。ReactXP は、iOS/Android をターゲットとする場合は React Native に、ウェブをターゲットとする場合は react-dom にマッピングされるクロスプラットフォームコンポーネントのセットを提供します。ReactXP の目標は、React Native for Web と呼ばれる別のオープンソースライブラリと似ています。これらのライブラリのアプローチがどのように異なるかについては、ReactXP FAQ に簡潔な説明があります。

Shoutem

  • Shoutem を使用してアプリを構築する際の開発者体験を改善および簡素化するための取り組みを続けています。
  • すべてのアプリを react-navigation に移行し始めましたが、より安定したバージョンがリリースされるか、ネイティブナビゲーションソリューションのいずれかが安定するまで延期することにしました。
  • すべての 拡張機能 とほとんどのオープンソースライブラリ(animationthemeui)を React Native 0.47.1 に更新しています。

次のセッション

次回のセッションは 2017 年 9 月 13 日水曜日に予定されています。今回で 3 回目のミーティングだったので、これらのメモが React Native コミュニティにどのように役立っているかを知りたいです。ミーティングの成果をどのように改善すべきかについて提案があれば、お気軽に Twitter で私に連絡してください。

MarketplaceでのReact Nativeパフォーマンス

·6分で読めます
Facebook ソフトウェアエンジニア

React Nativeは、Facebookファミリーの複数のアプリの様々な場所で使用されており、主要なFacebookアプリのトップレベルタブでも利用されています。この投稿では、特に注目度の高い製品であるマーケットプレイスに焦点を当てます。これは十数カ国で利用可能で、ユーザーは他のユーザーが提供する製品やサービスを発見できます。

2017年前半、Relayチーム、Marketplaceチーム、モバイルJSプラットフォームチーム、React Nativeチームの共同努力により、Android Year Class 2010-11デバイスにおけるMarketplaceのTime to Interaction (TTI) を半減させました。Facebookはこれまで、これらのデバイスをローエンドのAndroidデバイスとみなしており、あらゆるプラットフォームやデバイスタイプの中で最もTTIが遅い状況でした。

典型的なReact Nativeの起動処理は次のようになります。

免責事項:比率は代表的なものではなく、React Nativeの設定や使用方法によって異なります。

まず、React Nativeコア(別名「ブリッジ」)を初期化し、その後プロダクト固有のJavaScriptを実行します。このJavaScriptが、ネイティブ処理時間内にReact Nativeがどのネイティブビューをレンダリングするかを決定します。

異なるアプローチ

我々が当初犯した間違いの一つは、SystraceとCTScanにパフォーマンスの取り組みを任せてしまったことでした。これらのツールは2016年に多くの簡単な改善点を見つけるのに役立ちましたが、SystraceとCTScanの両方が本番環境のシナリオを代表しておらず、実際の状況をエミュレートできないことがわかりました。内訳にかかる時間の比率はしばしば不正確で、時には大きくずれていました。極端な例では、数ミリ秒かかると予想されたものが、実際には数百、数千ミリ秒かかることもありました。とは言え、CTScanは有用であり、本番環境に到達する前に3分の1のリグレッションを捕捉することを発見しました。

Androidでは、これらのツールの欠点を1) React Nativeがマルチスレッドフレームワークであること、2) Marketplaceがニュースフィードや他のトップレベルタブなど、多数の複雑なビューと共存していること、3) 計算時間が大きく変動すること、に起因すると考えています。したがって、今期は、本番環境の測定値と内訳が意思決定と優先順位付けのほぼすべてを推進するようにしました。

本番環境計測の道のり

本番環境の計測は、一見するとシンプルに聞こえるかもしれませんが、かなり複雑なプロセスであることが判明しました。マスターへのコミットの遅延、Playストアへのアプリのプッシュ、作業に自信を持つための十分な本番サンプル収集のため、それぞれ2〜3週間の複数回のイテレーションサイクルを要しました。各イテレーションサイクルでは、内訳が正確であるか、適切な粒度であるか、そして全体の時間範囲に適切に加算されているかを確認する必要がありました。アルファ版やベータ版は一般人口を代表していないため、信頼できませんでした。本質的に、我々は数百万のサンプルの集計に基づいて、非常に正確な本番トレースを非常に骨の折れる作業で構築しました。

内訳の各ミリ秒が親メトリクスに適切に加算されていることを綿密に検証した理由の1つは、計測にギャップがあることに早期に気づいたためです。当初の内訳では、スレッドジャンプによって引き起こされるストールが考慮されていなかったことが判明しました。スレッドジャンプ自体は高価ではありませんが、すでに作業中のビジースレッドへのスレッドジャンプは非常に高価です。最終的に、適切なタイミングでThread.sleep()呼び出しを散りばめることでこれらのブロックをローカルで再現し、それらを修正することができました。

  1. AsyncTaskへの依存を削除
  2. UIスレッドでのReactContextとNativeModulesの強制的な初期化を取りやめ
  3. 初期化時にReactRootViewを測定する依存関係を削除

これらのスレッドブロッキングの問題を合わせて取り除くことで、起動時間が25%以上短縮されました。

本番環境のメトリクスは、これまでの仮定の一部にも疑問を投げかけました。たとえば、以前は、モジュールを1つのバンドルにまとめることで初期化コストが削減されるという仮定の下、起動パスで多くのJavaScriptモジュールを事前ロードしていました。しかし、これらのモジュールを事前ロードしてまとめるコストは、メリットをはるかに上回っていました。インラインrequireブラックリストを再構成し、JavaScriptモジュールを起動パスから削除することで、Relay Classic(Relay Modernのみが必要な場合など)のような不要なモジュールのロードを回避することができました。今日、RUN_JS_BUNDLEの内訳は75%以上高速化されています。

また、製品固有のネイティブモジュールを調査することでも成果がありました。たとえば、ネイティブモジュールの依存関係を遅延注入することで、そのネイティブモジュールのコストを98%削減しました。Marketplaceの起動と他の製品との競合を排除することで、起動を同等の時間短縮しました。

最も素晴らしい点は、これらの改善の多くがReact Nativeで構築されたすべての画面に広く適用可能であることです。

結論

人々は、React Nativeの起動パフォーマンスの問題は、JavaScriptが遅いことや、非常に長いネットワーク時間によって引き起こされると考えがちです。JavaScriptのようなものを高速化することは、TTIを無視できないほど削減しますが、これらのそれぞれがTTIに貢献する割合は、以前考えられていたよりもはるかに小さいです。

これまでの教訓は、「測定、測定、測定!」です。Relay ModernやLazy NativeModulesのように、実行時コストをビルド時コストに移行することで得られる成果もあります。また、コードの並列化やデッドコードの削除をより賢く行うことで、作業を回避することから得られる成果もあります。そして、スレッドブロックのクリーンアップなど、React Nativeへの大規模なアーキテクチャ変更から得られる成果もあります。パフォーマンスに壮大な解決策はなく、長期的なパフォーマンスの向上は、漸進的な計測と改善から生まれます。認知バイアスがあなたの意思決定に影響を与えないようにしましょう。代わりに、慎重に本番データを収集し、解釈して、将来の作業を導きましょう。

今後の計画

長期的には、MarketplaceのTTIをネイティブで構築された同様の製品と比較できるものにし、一般的にReact Nativeのパフォーマンスをネイティブのパフォーマンスと同等にしたいと考えています。さらに、今期はブリッジの起動コストを約80%大幅に削減しましたが、Prepackやより多くのビルド時処理などのプロジェクトを通じて、React Nativeブリッジのコストをゼロに近づける計画です。

React Nativeマンスリー #2

·9分で読めます
Tomislav Tenodi
Shoutem プロダクトマネージャー

React Nativeの月例会議は引き続き開催されています!今回のセッションでは、React NativeカンファレンスであるChain Reactの立役者であるInfinite Redの素晴らしい頭脳の持ち主たちが参加してくれました。参加者のほとんどがChain Reactで講演をしていたため、会議を1週間遅らせました。カンファレンスでの講演はオンラインで公開されているので、ぜひご覧ください。それでは、各チームの活動を見ていきましょう。

チーム

第2回となるこのミーティングには、9つのチームが参加しました。

ノート

以下は各チームからの議事録です。

Airbnb

Callstack

  • Mike Grabowskiは、いつものようにReact Nativeの月次リリースを管理しており、いくつかのベータ版もリリースされました。特に、Windowsユーザーのブロックを解除するv0.43.5ビルドをnpmに公開することに取り組んでいます!
  • Haulでは、ゆっくりではありますが着実な作業が進んでいます。HMRを追加するプルリクエストがあり、その他の改善も実施されました。最近、いくつかの業界リーダーに採用されました。この分野でのフルタイムの有給作業を開始する計画も検討しています。
  • JestチームのMichał Pierzchałaが今月、Callstackに参加してくれました。彼はHaulのメンテナンスを手伝い、おそらくMetro BundlerJestにも取り組む予定です。
  • Satyajit Sahooが私たちのチームに加わりました!イェイ!
  • 私たちのOSS部門から、たくさんのクールなものが登場予定です。特に、Material Palette APIをReact Nativeに導入する作業に取り組んでいます。ネイティブコンポーネントと1:1のルック&フィールを提供することを目的とした、ネイティブiOSキットを最終的にリリースする予定です。

Expo

  • React Nativeエコシステムにおけるライブラリの発見と評価を支援するために、最近Native Directoryを立ち上げました。問題点:多くのライブラリがあり、テストが難しく、手動でヒューリスティックを適用する必要があり、どれが最適なのかがすぐにわかりません。また、CRNA/Expoと互換性があるかどうかも判断が難しいです。そこで、Native Directoryはこれらの問題を解決しようとします。ぜひチェックして、あなたのライブラリを追加してください。ライブラリのリストはこちらにあります。これは私たちの最初の試みであり、Expoのメンバーだけでなく、コミュニティ全体で所有・運営されることを望んでいます。もしこれが価値があり、改善したいと思うのであれば、ぜひご協力ください!
  • Expo SDK 19のSnackにnpmパッケージをインストールするための初期サポートが追加されました。問題が発生した場合はお知らせください。現在もいくつかのバグに取り組んでいます。Native Directoryと合わせて、これによりJS依存関係のみ、またはExpo SDKに含まれる依存関係を持つライブラリのテストが容易になるはずです。試してみてください。
  • 全体的に多くの改善が施されたExpo SDK19をリリースしました。現在は更新されたAndroid JSCを使用しています。
  • Alexander Kotliarskyiとともに、アプリのユーザーエクスペリエンスを向上させるためのヒントリストをドキュメントのガイドとして作成しています。ぜひ参加してリストに追加したり、執筆を手伝ったりしてください!
  • 引き続き取り組んでいること:オーディオ/ビデオ、カメラ、ジェスチャー(Software Mansionとの協力、react-native-gesture-handler)、GLカメラ統合。これらのいくつかをSDK20(8月)で初めて導入し、他の機能もそれまでに大幅に改善することを目指しています。バックグラウンド作業(位置情報、オーディオ、通知処理など)のためのインフラストラクチャをExpoクライアントに構築し始めたばかりです。
  • Adam Miskiewiczは、UINavigationControllerのトランジションをreact-navigationで模倣することに素晴らしい進展を見せました。初期バージョンは彼のツイートで確認できます。まもなくリリースされます。彼がアップストリームしたMaskedViewIOSもチェックしてください。もしあなたがAndroid用のMaskedViewを実装するスキルと意欲があれば、素晴らしいことです!

Facebook

  • Facebookは内部的に、React Native内にネイティブのComponentKitLithoコンポーネントを埋め込むことを検討しています。
  • React Nativeへの貢献は大歓迎です!どのように貢献できるか疑問に思っている場合は、「貢献方法」ガイドで開発プロセスが説明されており、最初のプルリクエストを送信する手順が示されています。コードを書く必要のない貢献方法もあります。例えば、問題をトリアージしたり、ドキュメントを更新したりすることです。
    • 執筆時点では、React Nativeには635未解決の問題249未解決のプルリクエストがあります。これは私たちのメンテナーにとって非常に多いため、内部で修正された場合でも、関連するタスクが更新されていることを確認するのが困難です。
    • コミュニティを満足させつつ、これをどう処理するのが最善か、私たちにはまだ確信がありません。いくつかの(ただし全てではありません!)選択肢としては、古い問題をクローズする、より多くの人に問題管理の権限を与える、問題テンプレートに従わない問題を自動的にクローズする、などがあります。私たちは、期待を設定し、サプライズを避けるために「メンテナーに期待すること」ガイドを作成しました。メンテナーにとってこの経験をより良くし、問題を提起する人やプルリクエストを作成する人が、意見を聞かれ、評価されていると感じられるようにする方法についてアイデアがあれば、ぜひお知らせください!

GeekyAnts

  • Chain ReactでReact Nativeファイルに対応したデザイナーツールのデモを行いました。多くの参加者がウェイティングリストに登録してくれました。
  • また、React Native全体のパフォーマンスを向上させるために、アーキテクチャの違いやそこから学べることを理解するため、Google Flutter(主要な比較が控えています)、Kotlin NativeApache Weexなどの他のクロスプラットフォームソリューションも検討しています。
  • ほとんどのアプリでreact-navigationに切り替え、全体的なパフォーマンスが向上しました。
  • また、NativeBase Marketを発表しました。これはReact Nativeのコンポーネントとアプリのマーケットプレイスです(開発者のための、開発者による)。

Infinite Red

Microsoft

  • CodePushMobile Centerに統合されました。既存のユーザーのワークフローに変更はありません。
    • 一部の方から、アプリが重複しているという問題が報告されています。彼らはすでにMobile Centerにアプリを持っていました。これらの問題を解決するために取り組んでいますが、もし2つのアプリがある場合はお知らせください。こちらでマージすることができます。
  • Mobile Centerは現在、CodePushのプッシュ通知をサポートしています。また、通知とCodePushを組み合わせてアプリのA/Bテストを行う方法も紹介しました。これはReactNativeアーキテクチャに特有のものです。
  • VS CodeにはReactNativeに関する既知のデバッグの問題があります。数日中にリリースされる拡張機能の次のバージョンで、この問題が修正される予定です。
  • Microsoft内にはReact Nativeに取り組んでいる他の多くのチームもあるため、次回のミーティングではすべてのグループからより良い代表者を得られるよう努めます。

Shoutem

  • ShoutemでのReact Native開発を容易にするプロセスを完了しました。Shoutemでアプリを開発する際には、すべての標準的なreact-nativeコマンドを使用できます。
  • React Nativeでのプロファイリングに最適なアプローチを見つけるために、多くの作業を行いました。ドキュメントの大部分は古くなっており、公式ドキュメントにプルリクエストを作成するか、少なくともブログ投稿で私たちの結論を書き出すために最善を尽くします。
  • ナビゲーションソリューションをreact-navigationに切り替えているので、近々フィードバックがあるかもしれません。
  • ツールキットに新しいHTMLコンポーネントをリリースしました。これは生のHTMLをReact Nativeコンポーネントツリーに変換するものです。

Wix

  • react-native-repackagerの機能を備えたMetro Bundlerへのプルリクエストの作業を開始しました。react-native-repackagerを更新して、RN 44(本番環境で使用しています)をサポートするようにしました。これは、detox用のモックインフラストラクチャに使用しています。
  • Wixアプリでは、過去3週間Detoxテストを実施してきました。この規模(40人以上のエンジニア)のアプリで手動QAを減らす方法について、素晴らしい学習経験となりました。その結果、Detoxに関するいくつかの問題を解決し、新しいバージョンがリリースされたばかりです。これまでのところ、「ゼロ不安定性ポリシー」を順守しており、テストは一貫して合格していることを報告できて嬉しく思います。
  • Detox for Androidは順調に進んでいます。コミュニティから大きな助けを得ています。約2週間で初期バージョンが期待されます。
  • 私たちのパフォーマンステストツールであるDetoxInstrumentsは、当初の意図よりも少し大きくなっています。現在、Detoxと密接に連携しないスタンドアロンツールにすることを目指しています。これにより、一般的なiOSアプリのパフォーマンスを調査できるようになります。また、Detoxとも統合され、パフォーマンスメトリクスに関する自動テストを実行できるようになります。

次のセッション

次回のセッションは2017年8月16日に予定されています。今回がまだ2回目の会議であるため、これらのメモがReact Nativeコミュニティにどのように役立っているかを知りたいと考えています。会議のアウトプットを改善するための提案があれば、お気軽にTwitterで私に連絡してください。