React NativeにFastlaneを使って、FabricとCodePushにデプロイする

前提


FabticとCodePushはすでに使える状態

ディレクトリ構成


.
├── README.md
├── __tests__
├── app.json
├── build
├── fastlane
├── index.ios.js
├── ios
├── js
├── node_modules
└── package.json

プロジェクト名

HRKSample

要約


gymでworkspaceを指定、ipaをbuildディレクトリ配下に出力
crashlyticsでipa_pathの指定
code-pushのpluginを追加


Fastlane Plugin追加


fastlane/Pluginfile ファイルを作成


```
gem 'fastlane-plugin-code_push'
```

プラグインのインストール

$ fastlane install_plugins




Fastfile


Fablicへアップロード

  lane :beta do
    gym(
      workspace: 'ios/HRKSample.xcworkspace',
      scheme: "HRKSample",
      output_directory: "build",
    )
    crashlytics(
      ipa_path: "build/HRKSample.ipa",
      api_token: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
      build_secret: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    )
  end

code-pushへデプロイ

アクセスキーは ~/.code-push.config に設定済みのはず。

  desc "fastlane beta_app desc:\"update description\""
  lane :beta_app do |options|
    code_push_release_react(
      app_name: "hrk-sample",
      platform: "ios",
      description: options[:desc],
    )
  end

Let's Encryptを使って無料でHTTPS対応する

前提


CentOS release 6.9 (Final)

すでに httpでnginxが動いてる前提

勘違いしていた点

ドキュメントなどを見てると、nginxのプラグインを使うとか書いてあるが、
--webroot -w [nginxのルートディレクトリ]を指定すればOK


証明書作成コマンド


$ sudo ./certbot-auto certonly --webroot -w /usr/share/nginx/hogehoge -d foo-bar.com

作業ディレクトリを指定しなければ、ここに作成される
/etc/letsencrypt/live/[ドメイン名]/

nginxの設定


    ssl_certificate /etc/letsencrypt/live/foo-bar.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/foo-bar.com/privkey.pem;
    ssl_session_cache shared:SSL:1m;
    ssl_session_timeout  10m;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

fastlaneでデバイス登録

Fastlaneを使ってデバイスの登録を行い、Provisioning Profileへの追加、Xcodeの更新を行う

デバイスの追加

register_devicesで追加

Provisioning Profileの更新

sigh で更新

adhocやdevelopmentの指定が可能

```
    # Adhoc
    sigh(force: true, adhoc: true)
    # Development
    sigh(force: true, development: true)
```

Xcodeの設定の更新

update_project_provisioningで更新

ビルドの指定や、ファイル名の指定が可能

```
    update_project_provisioning(build_configuration: "Debug")
```


現時点でのFastfaile



```
  desc "Register Device"
  lane :add_device do |options|
    if options[:name] && options[:udid]
      register_devices(devices: {options[:name] => options[:udid]})
      update_develop_provisioning()
      update_adhoc_provisioning()
    else
      UI.error "Usage: fastlane add_device name:'New device name' udid:'UDID'"
    end
  end

  desc "update developmemt provisioning profile"
  lane :update_develop_provisioning do
    sigh(
      force: true,
      development: true,
      output_path: "provisioning",
      filename: "development.mobileprovision"
    )
    update_project_provisioning(
      build_configuration: "Debug",
      profile: "provisioning/development.mobileprovision",
    )
  end

  desc "update adhoc provisioning profile"
  lane :update_adhoc_provisioning do
    sigh(
      force: true,
      adhoc: true,
      output_path: "provisioning",
      filename: "adhoc.mobileprovision"
    )
    update_project_provisioning(
      build_configuration: "Release",
      profile: "provisioning/adhoc.mobileprovision",
    )
  end
```

使い方
fastlane add_device name:'hrk iPhone7' udid:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx





React NativeのAnimationについて

react nativeのアニメーションには2つのやり方がある

Animatedを使う場合と、LayoutAnimationがある

Animated

AnimatedはView, Text, Image, ScrollViewの4つのコンポーネントをexportしている

Animated.createAnimatedComponent()を使って独自のコンポーネントを作成することも可能

例:

```
class FadeInView extends React.Component {
  state = {
    fadeAnim: new Animated.Value(0),  // 0で初期化する
  }

  componentDidMount() {
    Animated.timing(                  // 
      this.state.fadeAnim,            // 変化させる値
      {
        toValue: 1,                   // どこまで変化させるか
        duration: 10000,              // どれくらい時間かけるか
      }
    ).start();                        // アニメーション実行
  }

  render() {
    let { fadeAnim } = this.state;

    return (
     
        style={{
          ...this.props.style,
          opacity: fadeAnim,    
        }}
      >
        {this.props.children}
     
    );
  }
}
```


setStateを呼び出して再レンダリングするよりも高速

オプション

Animated.timing
easing: エフェクトの動き
delays 遅延実行 (ミリ秒)


アニメションの順番

アニメーションの同時実行や、直前のアニメーションが終わってから実行させるように設定することも可能

Animated.sequence 順番にアニメーションさせる
Animated.parallel 同時にアニメーションさせる



補完


Animation.Valueの値を別の値で置き換える
例: 0-1の値を0-100に置き換える

value.interpolate({
  inputRange: [0, 1],
  outputRange: [0, 100],
});

必ずしも線形にする必要はない

value.interpolate({
  inputRange: [-300, -100, 0, 100, 101],
  outputRange: [300,    0, 1,   0,   0],
});

Input | Output
------|-------
  -400|    450
  -300|    300
  -200|    150
  -100|      0
   -50|    0.5
     0|      1
    50|    0.5
   100|      0
   101|      0
   200|      0

数字から文字に変換も可能

value.interpolate({
  inputRange: [0, 360],
  outputRange: ['0deg', '360deg']
})



スクロールに合わせて動かす


パラメータ
  state = {
    scrollY: new Animated.Value(0),
  }

Scroll実装

       
          scrollEventThrottle={16}
          onScroll={Animated.event(
            [{ nativeEvent: { contentOffset: { y: scrollY } } }]
          )}
          >

対象のView

       
          style={{
            position: 'absolute',
            top: 30,
            right: 0,
            transform: [{
              translateY: Animated.multiply(scrollY, -1)
            }],
          }}
        >
          Hoge
       

Animated.multiplyは-1で掛け算してる

PanGestureのイベント

onPanResponderMove={Animated.event(
  [null, // ignore the native event
  // extract dx and dy from gestureState
  // like 'pan.x = gestureState.dx, pan.y = gestureState.dy'
  {dx: pan.x, dy: pan.y}
])}

Native Driver


ネイティブ側でアニメーションを実行する
アニメーション中もJSのスレッドがブロックされることはない

ScrrollViewの例

       
          scrollEventThrottle={16}
          onScroll={Animated.event(
            [{ nativeEvent: { contentOffset: { y: scrollY } } }],
            { useNativeDriver: true }
          )}
          >

LayoutAnimation


全てのレイアウト変更に対するアニメーションに便利
flex-boxのレイアウトなど。
ただしできることが少ない

    LayoutAnimation.linear();
    this.setState({ w: this.state.w + 15, h: this.state.h+15 })

Google DataStoreのID管理について

前提

DataStoreは分散してデータを保存しているため、データ数が膨大になっても、
パフォーマンスが落ちることがない。

ただし、その分考慮しないといけない部分も多い

連番

基本的には使えない、データを複数拠点で管理しているため、同期をとろうとすると、パフォーマンスがボトルネクになるため、オートインクリメントなどはない。

また連番にすると、データの格納先が分散されないため、そもそも良くない。


要件

連番表示

それでも人が作業する場合に、管理IDなるものは連番の方が何かと処理しやすかったりする。

なのでデータの保存用のIDと表示用のIDを準備して対応する。

事前のID取得

IDに紐づいてファイル名などを決定したい(別でファイル名作ってもいいけど・・・)


連番の生成方法

その1

連番はmemcachedでインクリメント
※ここって整合性は保証される?

その2

連番はCloud SQLを使うmysqlのMyISAMでシーケンステーブルを作成


事前のID取得

その1

DataStoreにKey専用のEntityを作る
- UserID IDの発番用に使う
- User

その2

UUIDを使う?

GAE/goからFirebase Cloud Messagingを使う

ライブラリの選定

色々なオープンソースを使わせてもらい感謝してます!

star: 91 最終更新2/6

star: 12 最終更新5/12

star: 14 5/18


今回はGAEで使うため、httpクライアントを差し替えれるものを使いたかった。
あと、コードを見てみると、送信用のパラメータが一通り揃っているedganiukovさんの
ライブラリが良さそう

実装


func SendNotification(ctx context.Context, body string) error {

token := "sample_token"
// or
tokens :=[]string{  "sample_token", "sample_token2" }


msg := &fcm.Message{
Notification: &fcm.Notification{
Body:  body,
Badge: "1",
},
}

if len(tokens) == 1 {
msg.Token = token
} else {
msg.RegistrationIDs = tokens
}

// Create a FCM client to send the message.
o := fcm.WithHTTPClient(urlfetch.Client(ctx)) // GAEようにhttp clientを差し替える
client, _ := fcm.NewClient(os.Getenv("FIREBASE_API_KEY"), o)

// Send the message and receive the response without retries.
response, err := client.Send(msg)
if err != nil {
return err
}

log.Debugf(ctx, "%+v", response)

return nil
}

DataStoreの辛いところ

# DataStoreの限界 FacebookやインスタグラムのようなSNSで、投稿、公開範囲、お気に入りなどの機能をDataStoreで実現しようとするとどうしても辛くなる。 ## DataStoreで実現可能? - users - id - feeds - i...