React Native renderの更新タイミング調査

目的

React Nativeで、reduxとreact-navigationを使ってるとやたらとrenderが走る。
タブやナビゲーションの親のViewでもレンダリングされているので、一度詳しく調べてみる。

調査


react-nativeのReact.PureComponentとは

PureComponentはComponentのshouldComponentUpdateを変更したもの。
shallowの比較により、Updateするか決める。

サンプルコード


```
// 通常のComponentクラス
class Normail extends React.Component {
  constructor(props) {
    super(props)
    this.render_num = 0
  }

  render() {
    this.render_num++
    return (
     
        normail
        {this.render_num}
     
    );
  }
}

// PureComponentクラス
class Pure extends React.PureComponent {

  constructor(props) {
    super(props)
    this.render_num = 0
  }

  render() {
    this.render_num++

    return (
     
        pure
        {this.render_num}
     
    );
  }
}


export default class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      param1: "hoge",
      param2: { "hoge": "val" },
    }
  }

  render() {
    const {param1, param2} = this.state
    return (
     
       
       
       
       
       
     
    );
  }
}
```

Propの値がどう変わるかで挙動が変わる

文字列や数字の場合

this.setState({ param1: "hoge" })を実行すると

React.Componentはレンダリングされる
React.PureComponentはレンダリングされない!

同じObjectの場合

this.setState({ param2: this.state.param2 })

React.Componentはレンダリングされる
React.PureComponentはレンダリングされない!

中身は同じObjectの場合

this.setState({param2: {"hoge": "val"}})

React.Componentはレンダリングされる
React.PureComponentはレンダリングされる


PureComponentはただのshallowEqualなので、第一階層だけしか比較できない


該当コードにあるように、shallowEqualをつかって比較している。
shallowEqualはFacebookのやつ


ここのメソッドで第一階層しかチェックしてない。まぁパフォーマンスを考えるとしかたないのかな・・・

iOS11アプリ起動中にPush通知が受け取れない

iOS10からUserNotificationが導入されて、RemoteNotificationと共存している時に、iOS11ではアプリがForegroundにいる時に通知が取得できない状態になっていた。


```
  func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
     // ここで処理を行う

  }
```

iOS10までは、UserNotificationも上記が呼ばれる

iOS11ではUNUserNotificationCenterDelegateを実装しないと呼ばれない

```
    @available(iOS 10.0, *)
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {

      // ここで処理を行う

      completionHandler([])

    }
```

アプリ起動時もUserNotificationを表示させたい場合はcompetionHandler([.badge, .alert, .sound])とすると、表示される。

そのをたっぷすると、上のdidReceiveRemoteNotificationあ呼ばれる

GAE DataStoreバックアップ&リストア方法

https://cloud.google.com/datastore/docs/console/datastore-backing-up-restoring?hl=ja

1. 書き込み制限

ドキュメントに書いてあるのは書き込みを向こうにする・・・

そうすると、全部のデータストアが書き込み向こうになるので、一旦この設定は見送り

書き込み制限をすると、全てのエンティティーでエラーとなる

2.バックアップ作成

バックアップしたいエンティティを選択してバックアップを作成

バックアップ名の入力があるので、基本そのまま保存する

保存先のGoogle Cloud Storageが登録されていない場合、エラーとなるので、
バックアップようのパケットを作成する

3.リストア

バックアップから選択してリストする

(バックアップから復元する場合、バックアップ後に登録したデータが削除されるわけではない)

react nativeでxcodeのconfigurationを追加(Adhocなど)している時のハマりポイント

新しくreact-nativeのライブラリを追加して、linkを通しても、Adhocビルドが通りません。

例えば以下のようにライブラリを追加すると

```
npm install react-native-image-picker@latest --save
react-native link
```











Configurationを追加してあげないといけない。

GAE/goのログを分析可能にする

#ストレージ先

- BigQuery
- Cloud Storage

https://cloud.google.com/logging/docs/export/using_exported_logs?hl=ja

##  BigQuery

検索しやすい
料金はCloud Storageより高い
$0.02/GB (90日アクセエスないと $0.01/GB)

## Cloud Storage

検索は不向き
料金は安い
1時間に1回、一括で行われる
東京 Reagional Storage $0.023/GB Nealine Storage $0.016


# 保存形式

## BigQuery

リクエストログになるため、1リクエストに対して出力したログを全て1つのjsonにかくのうされる

そのためそのままBigQueryに登録しようとすると、余計なログまで格納される

# Cloud Storage

Cloud Storageに出力されるログも同様に全データが出力される。
Cloud StorageからBigQueryにインポートする場合、カラムの絞り込みを行う必要がある。
また定期実行の仕組みが必要


# まとめ

Cloud Storageを使うメリットがあまりないので、GAE => BigQuery => BigQuery中間テーブルを作成するのが楽そう

golangでバーコード作成


star: 284
https://github.com/boombuler/barcode

いろいろ調べようとおもったけど、あまり種類がなさそうなので、ひとまず上記のやつを使ってみる


バーコードのライブラリ一覧
https://golanglibs.com/top?q=barcode

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
}

Railsのアソシエーションで名前が違う場合の対処法

Railsのモデル名にLoveなどをつけた場合、has_many: lovesと指定すると、Railsはloves => lofeと変換してしまう。

これを正しくするには、inflections.rbに追記する。
config/initializers/inflections.rb

```
ActiveSupport::Inflector.inflections(:en) do |inflect|
  inflect.irregular "love", "loves"
end
```


React Native Nclideでデバッグできない時の対処法

React Nativeの開発環境の構築でハマったのでメモ

atom nuclideでデバッグ


下準備と手順が大切?

1. (atom) packager start
2. (cmd) react-native ios-run
3. (atom) debugger start
4. シミュレータのDebug JS Remotelyを選択

多分だけど、chromeのdebuggerが起動してあると、そっちと接続してしまうので、
そこだけ気をつけてればすぐにつながったかも。

React Native react-native-router-fluxを使って開発も楽にする!

React Nativeのページ遷移をreact-native-router-fluxを使ってると、開発段階でもすごく効率よく開発できる。

例えば、ページが深い所にある場合、再起動してそのページに遷移するのが面倒になる。
でもreact-native-router-fluxのinitialを指定すれば、そのページから起動することが可能

react-native-router-fluxで例を見ると

```

 
   
     
     
       
       
     
     
     
     
      initial
/>     
       
       
       
     
     
       
         
           
           
         
         
           
           
         
         
         
         
       
     
   
   
 

```

tab2_2の画面を表示したい場合、launchが初回表示され、
「tabbar」=> 「tab2」=>「tab2_2」のようタップする必要がある。

これを以下のように指定すると、起動時にtab2_2が表示される。

```
 
   
     
     
       
       
     
     
     
     
     
     
       
       
       
     
      initial
>
       
         
           
           
         
          initial
>
           
            initial
/>
         
         
         
         
       
     
   
   
 
```


atom インストール済みパッケージの確認

インストール済みのパッケージ一覧

```
$ apm list
Built-in Atom Packages (90)
├── atom-dark-syntax@0.28.0
├── atom-dark-ui@0.53.0
├── atom-light-syntax@0.29.0
├── atom-light-ui@0.46.0
├── base16-tomorrow-dark-theme@1.5.0
├── base16-tomorrow-light-theme@1.5.0
├── one-dark-ui@1.9.2
├── one-light-ui@1.9.2
├── one-dark-syntax@1.7.1
├── one-light-syntax@1.7.1
├── solarized-dark-syntax@1.1.2
├── solarized-light-syntax@1.1.2
├── about@1.7.5
├── archive-view@0.63.0
├── autocomplete-atom-api@0.10.0
├── autocomplete-css@0.15.1
├── autocomplete-html@0.7.2
├── autocomplete-plus@2.34.2
├── autocomplete-snippets@1.11.0
├── autoflow@0.29.0
├── autosave@0.24.0
├── background-tips@0.26.1
├── bookmarks@0.44.2
├── bracket-matcher@0.85.3
├── command-palette@0.40.3
├── dalek@0.2.0
├── deprecation-cop@0.56.2
├── dev-live-reload@0.47.0
├── encoding-selector@0.23.2
├── exception-reporting@0.41.2
├── find-and-replace@0.207.3
├── fuzzy-finder@1.5.0
├── git-diff@1.3.3
├── go-to-line@0.32.0
├── grammar-selector@0.49.3
├── image-view@0.61.1
├── incompatible-packages@0.27.2
├── keybinding-resolver@0.36.3
├── line-ending-selector@0.6.2
├── link@0.31.2
├── markdown-preview@0.159.7
├── metrics@1.2.1
├── notifications@0.66.2
├── open-on-github@1.2.1
├── package-generator@1.1.0
├── settings-view@0.248.0
├── snippets@1.1.1
├── spell-check@0.71.3
├── status-bar@1.8.5
├── styleguide@0.49.3
├── symbols-view@0.115.2
├── tabs@0.104.2
├── timecop@0.36.0
├── tree-view@0.215.1
├── update-package-dependencies@0.11.0
├── welcome@0.36.2
├── whitespace@0.36.2
├── wrap-guide@0.40.0
├── language-c@0.57.0
├── language-clojure@0.22.2
├── language-coffee-script@0.48.5
├── language-csharp@0.14.2
├── language-css@0.42.1
├── language-gfm@0.88.1
├── language-git@0.19.0
├── language-go@0.43.1
├── language-html@0.47.2
├── language-hyperlink@0.16.1
├── language-java@0.27.0
├── language-javascript@0.126.1
├── language-json@0.19.0
├── language-less@0.31.0
├── language-make@0.22.3
├── language-mustache@0.13.1
├── language-objective-c@0.15.1
├── language-perl@0.37.0
├── language-php@0.37.5
├── language-property-list@0.9.1
├── language-python@0.45.2
├── language-ruby@0.70.5
├── language-ruby-on-rails@0.25.2
├── language-sass@0.58.0
├── language-shellscript@0.25.0
├── language-source@0.9.0
├── language-sql@0.25.4
├── language-text@0.7.2
├── language-todo@0.29.1
├── language-toml@0.18.1
├── language-xml@0.35.0
└── language-yaml@0.29.0


Community Packages (13) /Users/xxxxxxxxxxx/.atom/packages
├── atom-beautify@0.29.19
├── atom-jshint@2.0.0
├── atom-react-native-autocomplete@0.0.27
├── busy-signal@1.3.0
├── intentions@1.1.2
├── jshint@1.8.6
├── language-javascript-jsx@0.3.7
├── linter@2.1.4
├── linter-eslint@8.1.6
├── linter-ui-default@1.2.3
├── rails-transporter@1.3.0
├── react@0.16.2
└── vim-mode@0.66.0
```


Atom Package Managerの略かな?

nuclideをアンインストールすると、左側に出ているproject navigatorみたいなウィンドウが表示されなくなり、色々調べていたら、設定 > Packages > Core Packagesのtree-viewがdisabledになってただった。

mysql2のインストール失敗 An error occurred while installing mysql2 (0.4.5), and Bundler cannot continue.

rails5をインストールするときにmysql2のgemがうまく入らずにハマった時のメモ

mac 10.12.3
ruby 2.3.1p112
Bundler version 1.12.5

```
Installing mysql2 0.4.5 with native extensions

Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

    current directory: /workdir/vendor/bundle/ruby/2.3.0/gems/mysql2-0.4.5/ext/mysql2
/Users/yoshifuji.hiroki/.rbenv/versions/2.3.1/bin/ruby -r ./siteconf20170415-12041-6ex24h.rb extconf.rb
checking for rb_absint_size()... yes
checking for rb_absint_singlebit_p()... yes
checking for ruby/thread.h... yes
checking for rb_thread_call_without_gvl() in ruby/thread.h... yes
checking for rb_thread_blocking_region()... no
checking for rb_wait_for_single_fd()... yes
checking for rb_hash_dup()... yes
checking for rb_intern3()... yes
checking for rb_big_cmp()... yes
-----
Using mysql_config at /usr/local/bin/mysql_config
-----
checking for mysql.h... yes
checking for SSL_MODE_DISABLED in mysql.h... no
checking for MYSQL_OPT_SSL_ENFORCE in mysql.h... no
checking for errmsg.h... yes
checking for mysqld_error.h... yes
-----
Don't know how to set rpath on your system, if MySQL libraries are not in path mysql2 may not load
-----
-----
Setting libpath to /usr/local/Cellar/mysql/5.6.26/lib
-----
creating Makefile

To see why this extension failed to compile, please check the mkmf.log which can be found here:

  /workdir/vendor/bundle/ruby/2.3.0/extensions/x86_64-darwin-15/2.3.0-static/mysql2-0.4.5/mkmf.log

current directory: /workdir/vendor/bundle/ruby/2.3.0/gems/mysql2-0.4.5/ext/mysql2
make "DESTDIR=" clean

current directory: /workdir/vendor/bundle/ruby/2.3.0/gems/mysql2-0.4.5/ext/mysql2
make "DESTDIR="
compiling client.c
compiling infile.c
compiling mysql2_ext.c
compiling result.c
compiling statement.c
linking shared-object mysql2/mysql2.bundle
ld: library not found for -lssl
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [mysql2.bundle] Error 1

make failed, exit code 2

Gem files will remain installed in /workdir/vendor/bundle/ruby/2.3.0/gems/mysql2-0.4.5 for inspection.
Results logged to /workdir/vendor/bundle/ruby/2.3.0/extensions/x86_64-darwin-15/2.3.0-static/mysql2-0.4.5/gem_make.out
Using puma 3.8.2
Using bundler 1.12.5
Using sass 3.4.23
Using tilt 2.0.7
Using turbolinks-source 5.0.0
Using tzinfo 1.2.3
Using nokogiri 1.7.1
Using rack-test 0.6.3
Using sprockets 3.7.1
Using websocket-driver 0.6.5
Using mime-types 3.1
Using coffee-script 2.4.1
Using uglifier 3.2.0
Using rb-inotify 0.9.8
An error occurred while installing mysql2 (0.4.5), and Bundler cannot continue.
Make sure that `gem install mysql2 -v '0.4.5'` succeeds before bundling.
```

解決方法

xcode-select --install

xcodeのコマンドラインツールがインストールしてないだけだった。

xcodeのversionあげた場合とか気をつけたほうがよい。

Apple Watch用アプリケーションの開発(その1)

はじめてのApple Watch開発についてのメモ

ここを見ながら作っていく
https://developer.apple.com/jp/documentation/General/Conceptual/WatchKitProgrammingGuide/index.html#//apple_ref/doc/uid/TP40014969-CH8-SW1


将来的に作りたいものは、ランニング用のアプリだけど、それは次の機会に。


Watchアプリケーションバンドルと、WatchKitExtension バンドル

WatchアプリケーションバンドルはUIのみ
  - ストーリーボード
  - リソースファイルだけ

WatchKitExtension は状態管理、インターフェースの管理、ユーザ操作の応答を行う


Watchアプリケーションのアーキテクチャ
https://developer.apple.com/jp/documentation/General/Conceptual/WatchKitProgrammingGuide/DesigningaWatchKitApp.html#//apple_ref/doc/uid/TP40014969-CH3-SW1


コンプリケーション
  - 時計の画面に表示できる小さな可視要素
  - アプリはメモリーに常駐しており、起動が早い
  - バックグランドタスクを実行できる割り当て時間が増加する

リモート通知のテスト、デバッグ
  JSONペイロードデータを指定して、送信される。
  PushNotificationPayload.apps この仕組みは普通にiOSアプリにも欲しいな。


WatchKitExtensionのデリゲート
  - WKExtension
  - WKExtensionDelegate (AppDelegateみたいなやつ)
    呼び出されるクラスはInfo.plistで指定する


バックグランドタスク
  - システムから呼び出され、それぞれのタスクの処理を行う
    - アプリケーションを最新の状態に更新
    - スナップショットを更新するタスク
    - Watchs接続タスク(iOSから取得する)
    - NSURLSessionタスク

データの共有
  - 各バンドル(Watchアプリケーション、WatchKitExtensionの両方)に置く
  - WatchKitExtensionに置く、Watchアプリケーションからはアクセス可能なため。
  - ネットワーク経由でダウンロード(またはiOSから転送)して、共有グループコンテナに置く


ファイルの共有
  - WatchアプリケーションとWatchKit Extensionのファイルの共有はApp Groupsを使って行う

iOSとのデータのやり取りをWatch Connectivity Frameworkを使う
  - 一時的なデータはupdateAplicationContextを使う。送信が完了していない場合に、再度呼び出すと、前回のデータは破棄されて、新しい送信を始める
  - 確実に届けたい場合はtransferUserInfoを使う





 

GitHubのpull requestをコマンドから実行したい

やりたいこと

git commitした後に、featureブランチをpushして、ブラウザでpull requestを作るのが面倒くさいので、ターミナルを使ってそのままやりたい。

ググってみるとgithubから出てるhubというツールが良さそう

インストール

$ brew install --HEAD hub

.bashrcに以下を追加
eval "$(hub alias -s)"


GitHubエンタープライズの設定

github.com以外の場合、以下を実行 (github.my.exampla.orgがエンタープライズのドメイン)
$ git config --global --add hub.host github.my.example.org

使い方

$git pull-request

を実行すると、エディターが起動してpull requestを作成してくれる
help(git help pull-request)を見ると
  -b マージ先ブランチ
  -h マージ元ブランチ
  -m メッセージ
で指定可能

リリース用のpull requestも出したい

developにマージしたpull requestを元にmasterにリリースする用のpull requestもコマンドから実行したい

インストール

$ gem install git-pr-release

# 開発用ブランチをdevelopにする
$ git config --file .git-pr-release  pr-release.branch.staging develop

# APIトークンを追加
$ git config --file .git-pr-release  pr-release.token XXXXXXXXXXXXXX


作成されるファイル(.git-pr-release)

[pr-release "branch"]
        staging = develop
[pr-release]
        token = XXXXXXXXXXXXXXXXXXXX

使い方

$ git-pr-release


参考

iOS circleciのビルド時間を1/3にした話

前提


CircleCIの実行時間は17分から18分
主に時間がかかっているところは

checkout 1分
pod install 5分
build+upload(fabric beta) 9分


やったこと

前からやってみたかったcocoapodsをgit管理にする

変更前

.gitignore
    Pods/
    *.xcworkspace/


変更後

.gitignore
    # Pods/
    # *.xcworkspace/
    !Pods/**/vendor/


一部bundlerを使ってたので、vendorの除外を追加

結果


checkout 1分20秒
pod install なし
build+upload(fabric beta) 9分


Podsのコード分だけ、checkoutが時間かかるけど、5分かかってたのが20秒に短縮されたのは大きい。

あとはgit cloneしてそのままビルドできるところも良いかも。
cocoapodsのバージョンが違うとか、気にしなくて良いので。

Nike+ Run Clubのイベントに初参加してきた

Nike+ Run Club


ランニングするときに自分の記録を残しておきたいと始めたアプリ。
そこにイベントという項目があり、表参道店に行ってみんなで走ろう!って感じのやつです。

イベント情報

そしsてそれに初めて参加してみてすごく良かったので、感謝の意味をこめてブロクに書いておきます!

Nike+ Run Club 表参道


参加したセッションは表参道のキャットストリートだっけ?そっちの店舗。

参加したセッション



シューズレンタルあり、ナイキエアズームストラクチャー20履き心地よかったなー!

ランニング前

全体のスケジュール
開催時間
集合時間:19:34
開始時間:20:04
終了予定:22:00頃

時間にはわりとちゃんとしてる人なので、10分前に到着。
集合時間までに着替えとかおわってないといけないのかな?とか思いつつ早めに行きましたが、まだ受付前なのでまってください。って言われる・・・。

でもせっかくなので、始めてなんですけど、どんな感じですか?って質問すると、いろいろ丁寧に教えてくれたので、初心者アピールもできて良かったです。

19:34になったら、受付が始まって、申し込み用紙を記入して、着替え用の大きな袋を渡されて、2Fの一人用のテント or 試着室で着替えます。

テントは4つぐらいしかないので、すこし待ちます。

その後、ある程度人数が集まったらみんなでジョギングで代々木公園へ。


ランニング中

ちゃんとした?感じなので準備運動をしたり、今回のトレーニングプランの効果、背景などもろもろ説明がありました。
その後、ストレッチと準備運動を行い、トレーニングスタート。

400mx12本。始め200mをゆっくり走り、後半200mを早いペースで走る。
つぎは前半早く、後半ゆっくりの繰り返し。

なんと無料なのにドリンク付き!!!本当ありがとうございます。

今回初参加ということもあり、真ん中より少し下のレベル(3/7)で参加。

これがものすごくものたりない・・・。まぁさいしょなので。。。

ペースメーカー?の方についていく感じで走るので、ちょっと無理しながらついていくようなレベルでやりたかったと後悔。

次は6/7ぐらいのレベルでチャレンジする予定!


ランニング後

ジョギング+ウォーキングで表参道に戻り、クールダウン、ストレッチを行いみんなで写真撮影をして終了。

今度はみんな一斉に着替えなので、すごい長蛇の列。

もう諦めてそのままの格好で帰りました。まぁ自転車だったし。

まとめ

すごく満足です。なのでこうやってブログを書き、参加しようか迷ってる方がいたら、これを見てなんとなくイメージしてもらえたら嬉しいです。

格好は全身adidasでしたが、全然平気でした。

マイナスな点は若干拘束時間が長いところと、更衣室が少ないところ。別に外で着替えてもいんだけど。。。
5km走るだけなのに、2.5hぐらい時間とられるのはちょっと。

でも無料でここまでやってくれるNikeはめちゃくちゃ好きになりそう。

初めての参加だったけど、すごく楽しかったです。
また参加させてください!ありがとうございました!!!


smartwatch3 x iphone7 を使ってみた(設定編)

はじめに

ランニングに行くときに、どれくらい走ったか、どれくらいのペースだったかを調べたいと思っても、iPhoneをもって一緒に走るのは重たいし、なかなか固定できないので、スマートウォッチを使ってなんとかできないか調査してみる。

Apple Watch1

GPS機能がついていない。
ただし、Nike+ではペースや距離は計測可能。
Adidasのアプリは無理。

SmartWatch3

GPS機能ついてるんですが、iPhoneとの連携はあくまでも通知だけ。
そもそもiOS向けのアプリでAndroid Wearに対応しているのがない?

iPhoneとAndroid Wearの連携

iOS向けの専用アプリ。これを連携すれば、一通りの通知は確認できる。
アプリ毎の通知拒否も可能。
通知はわかるけど、中身はわからない(メールの本文など)

Google FitがAndroid Wear内にあるが、これはiOS向けにはアプリが展開されていないためiPhoneと連動はできない。

音楽の早送り、ボリューム調整も可能。


Android端末があれば、少しは変わると思う。


Genymotionで連携できるかなーって思ったらどうも無料版がなくなってるらしい。
Androidのエミュレータってどうしてるんだろう。。。

毎年恒例の今年はちゃんとブログを書きます!

毎年恒例のブログを書く宣言(多分自分は今年が初めて)をします。

本当は毎週一つは投稿しようと思ってたんですが、残念ながら一発目からなかなか筆が進まず・・・。

iOSのライブラリで便利そうなものがあったので、それの調査をしながら書こうとおもってたのですが、最近ランニングにはまってしまい、日々のランニングをアプリを使って管理したいなー、どうせなら体力作りしたいから、少し負荷をかけたいなーとか考えてると、アプリやガジェットが気になりだして、結局アウトプットができずじまい。

なので、まず一発目は所信表明と書くということでひとまずかたずける事にしました。


でもついでなので、現状わかっていることを。

日々の活動を記録するアプリについて。

1. adidas Train & Run
http://japan.adidas.com/micoach

2. nike+ run club
http://www.nike.com/jp/ja_jp/c/nike-plus/running-app-gps
nike+traning club
http://www.nike.com/jp/ja_jp/c/nike-plus/training-app


adidasはランとトレーニングが一体になっており、nikeはランとトレーニングは別々になっています。

どちらも自分にあったランニング、トレーニングプランを選択して、カレンダーに日々のトレーニングのプランが登録されます。


adidasアプリ
  - 心拍数 or 距離ベースでペースを上げたり、さげたりするトレーニングがある
  - トレーニングの説明は文章で、トレーニングが終わるたびにタップして進む(スムーズに進めない)
  - Apple watchに対応していない

nike+アプリ
  - ランはまだちゃんとためせていないけど、adidasのようなペースを変化させるトレーニングはない?
  - トレーニングは実際のコーチが行ってる動画で説明されるのでわかりやすい
  - トレーニング開始すると、全部かってに進むため、スムーズにすすむ
  - runはapple watchだけでも計測可能

 
どちらも正しくトラッキングしようとするとiphoneを持ち歩かないといけないが辛いところ。以前はアームバンドを使ってiPhoneを持って走ってたけど、腕が疲れて半分で左右を逆に付け直すなど、ちょっとストレスだったので、今度はウエストバンドにしようかな。

あとBluetoothイヤホンをかったので、コードのストレスがなくなったのはすごく良い!


なんかだらだらと書いてましたが、今年はいろいろな目標を継続的につづけられるように頑張ります!

- 常に前に
- ルーティーン
- アウトプット

DataStoreの辛いところ

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