Expo のビルドで発生する Unable to find a specification for `UMCore` depended upon by `EX**` について
この記事は React Native Advent Calendar 2021 の10 日目の記事です。
Expo 歴 1 ヶ月ぐらいなので記述に間違いがあるかもしれないですが、同じエラーに悩んでいる方向けのヒントになればと思い公開。
環境
- expo 42 -> 43 に更新する際に発生
- managed work flow
事象
iOS 向けに Expo Build を実行し、expo.dev の Logs を確認すると、Install Pods で Unable to find a specification for UMCore
depended upon by EXScreenOrientation
というエラーが出てビルドに失敗した。
解決
Expo SDK 43 から、react-native-unimodules
が 非推奨になり、expo-modules-core と expo-modules-autolinking を利用するようになった。
react-native-unimodules
に依存しているパッケージ (このエラーの例だと、expo-screen-orientation
) が存在する場合に、このエラーが発生するようだ。
流石にこれらのパッケージを 1つずつ確認して更新や、対応していない場合は削除等の対応を行うのは大変なので、移行用ツールが提供されているようだ。
$ expo upgrade 43 Your git working tree is clean To revert the changes after this command completes, you can run the following: git clean --force && git reset --hard ✔ You are already using the latest SDK version. Do you want to run the update anyways? This may be useful to ensure that all of your packages are set to the correct version. … yes ✔ Validated configuration. ✔ No additional changes necessary to app config. ✔ Updated known packages to compatible versions. ✔ Cleared packager cache. Failed to query all project files. Skipping `.expo.*` extension check... ✔ Validated project 👏 Automated upgrade steps complete. ...but this doesn't mean everything is done yet! ✅ The following packages were updated: @react-native-async-storage/async-storage, react-native-safe-area-context, react-native-reanimated, react-native-gesture-handler, expo-updates, react-native-unimodules, expo-status-bar, react-native-svg, expo-linking, react-native-screens, expo-splash-screen, react-native-pager-view, expo-app-loading, expo-dev-client, react-native, react, react-dom, typescript, @babel/core, @types/react, react-native-web, @types/react-native, expo 🚨 The following packages were not updated. You should check the READMEs for those repositories to determine what version is compatible with your new set of packages: @expo/html-elements, @expo/match-media, @react-navigation/bottom-tabs, @react-navigation/drawer, @react-navigation/material-top-tabs, @react-navigation/native, @react-navigation/stack, @types/react-native-snap-carousel, native-base, react-helmet-async, react-native-responsive-screen, react-native-safe-area-view, react-native-snap-carousel, react-native-tab-view, react-responsive, recoil, recoil-persist, styled-components, styled-system, use-media, @react-navigation/devtools, @typescript-eslint/eslint-plugin, @typescript-eslint/parser, @welldone-software/why-did-you-render, babel-loader, deepmerge, eslint, eslint-config-prettier, eslint-plugin-prettier, eslint-plugin-react, eslint-plugin-react-hooks, prettier, react-devtools, react-native-flipper ⬆️ To finish your react-native upgrade, update your native projects as outlined here: https://react-native-community.github.io/upgrade-helper/?from=0.63.4&to=0.64.3 🏗 Run pod install in your iOS directory and then re-build your native projects to compile the updated dependencies. Please refer to the release notes for information on any further required steps to update and information about breaking changes: https://blog.expo.dev/expo-sdk-43-aa9b3c7d5541
このように、expo upgrade 43
することで、自動的に SDK 43 対応のパッケージに更新してくれる。ただし、自動更新の対象になっていないパッケージもある(The following packages were not updated.
)
これらについては、EAS Build を行ってエラーが出る度に 1つずつ対応していくか、node_modules 内をUMCore
で grep してエラーになりそうなパッケージを探していくかする必要がある。
自分の場合は、grep で@expo/match-media
のコードがマッチしたためパッケージを確認したが特に対応されていなそうだったのと、現時点で利用していなかったのでパッケージ自体を削除した。なお、今確認すると SDK 43 対応の PR はマージされているが、npm に対して publish はされていなさそう。v0.2.0 がどの時点のコミットなのかも分からなかった。
まとめ
以上の対応を行うことで、Unable to find a specification for UMCore
depended upon by EX**
のエラーは発生しなくなった。
おすすめの .gitconfig 設定
おすすめの .gitconfig 設定、といってもそんなにマニアックなものでもないが何も設定してないという方向けに参考になれば。
[alias] co = checkout [push] default = current [core] ignorecase = true [fetch] prune = true
[alias] co = checkout
開発業務をしていると、1日に何度も git checkout
する。ブランチを切り替える、ブランチを作成する、ファイルの編集内容を破棄する等何かと使う。
しかし、よく使うコマンドの割には checkout の文字数は長いので、git co
にしている。
[push] default = current
ローカルで新規に作成したブランチを push する際に、git push origin feature/xxx
というコマンドを打つ必要がなくなる。origin 以外を指定したいとき、別のブランチを指定したいことがないのでこれにしている。
[core] ignorecase = true
適宜変更はするが、macOS に合わせている。
[fetch] prune = true
git fetch
と同時に remote に存在せず local に存在するブランチを削除する。
- ローカルにブランチが蓄積されていくデメリット
- 間違って remote ブランチだけ削除してしまってもローカルから復旧可能なメリット
を天秤にかけて、自動的にブランチが整理されていく方を取った。ローカルから復旧できないことが致命傷になることもあるとは思うがチーム開発ならメンバー全員が削除してない限りは何とかなるでしょ多分。(他力本願)
Android バージョン毎の WebView と Chrome の対応表
自分用に整理していたが、けっこう有用かもしれないので公開する。
バージョン | Name | WebView更新*1 | WebView 依存アプリ*2 | Chrome バージョン*3 | リリース日 |
---|---|---|---|---|---|
4.1-4.3 | KitKat | 不可 | - | Chrome ベースではない | 2012年7月9日 |
4.4 | KitKat | 不可 | - | Chrome Android version 30 | 2013年10月31日 |
4.4.3 | KitKat | 不可 | - | Chrome Android version 33 | - |
5 | Lollipop | 可能 | Android System WebView | 最新を利用可能 | 2014年11月12日 |
6 | Marshmallow | 可能 | Android System WebView | 最新を利用可能 | 2015年10月5日 |
7 | Nougat | 可能 | Chrome | 最新を利用可能 | 2016年8月22日 |
省略 | - | - | - | - | - |
12 | - | 可能 | Chrome | 最新を利用可能 | 2021年10月4日 |
要約
- Android バージョン 4 の WebView に対応することは、Chrome 33 以下に対応することを意味するので注意しよう
- Android バージョン 5~6 と 7 以降では、WebView のブラウザ機能を更新可能ではあるが、依存する(更新する)アプリケーションが違うので注意しよう
Android Emulator について
- Android バージョン 5 以降の WebView を検証する際には、エミュレータの Android System WebView と Chrome のバージョンが古い可能性があるので注意しよう
- (参考)エミュレータの Android バージョン毎の対応表
参考
- https://developer.chrome.com/docs/multidevice/webview/
- https://en.wikipedia.org/wiki/Android_(operating_system)
*1:JavaScript エンジン、レンダリングエンジン等のブラウザ機能を更新することが可能かどうか
*2:JavaScript エンジン、レンダリングエンジン等のブラウザ機能を更新するために何のアプリを更新すればいいか
自分が購読しているテックブログ一覧2021
自分がどうやって技術系のインプットを行っているかについて書く。
いつ
休日。平日はほぼ見ない(週に1~2 時間でインプットが完了するように量を調整している)
どうやって
何を
大まかに分けると3つ
企業のテックブログを読む理由は一言で言うと自分の業務に役立つから。
- 技術選定の事例
- 開発プロセス等の取り組み
など、書籍からは得にくい”現実の(主に日本の) IT 企業" の現場の動きを観測している。
加えて、自分が所属企業でブログを書く際に
- どういうことをテーマにしたら需要がありそうか
- 同じテーマで既に公開されている記事がどんな内容か
などを知っている方が良い記事が書けるので日常的にテックブログを読んでおくのは役に立つ。
やらないこと
逆に、デイリーのニュースフロー的なものとか、ポエムっぽいものとかは自分の中で優先度が低いので読まない。(はてなのテクノロジーカテゴリ、GitHub トレンド等)
一覧
Inoreader からエクスポートした。
おまけ
Inoreader は フィードを xml でエクスポート/インポートできる。上記の表は、エクスポートした xml を json に変換してシェルで加工して作成した。
以下のコマンドを実行すると表のヘッダーより下の部分を生成できる(ファイル j
には 変換した json を用意)
$ paste -d '|' <(cat j | jq -r '.opml.body.outline[]."-text"') <(cat j | jq -r '.opml.body.outline[]."-htmlUrl"') | sed -e 's/.*/|&|/g' |LIVESENSE ENGINEER BLOG|https://made.livesense.co.jp/| |Pulp Note|https://pulpxstyle.com/| ...
今回 Inoreader から エクスポートした xml は gist で公開しているので、多分インポートに使えるはず(試してはない)
https://gist.github.com/pokuwagata/eae3f30e2539f1f0de7e54615caaafd6
img タグからのリクエストは Origin ヘッダーを持たないのでレスポンスの Access-Control-Allow-Origin を満たしていなくても CORS 違反にならないらしいという話
歴史的経緯により img タグからのリクエストは(crossorigin 属性を付与しない限り)クロスオリジンの場合でも preflight リクエストは飛ばない。これを simple request と呼ぶことは知っていた。
しかし、画像のレスポンスヘッダーに例えばAccess-Control-Allow-Origin: https://hoge.com
が含まれる場合に、hoge.com
以外から img タグを利用してリクエストを送ると CORS 違反になるんじゃないかと思っていた。
しかし実際に試してみたら、そのような画像に対して、img タグからリクエストを発行すると正常に画像を取得することができることが分かった。
例えば、localhost で以下のコードを動かすと画像が正常に表示される。
はてブ数を表示する画像 URL はレスポンスに Access-Control-Allow-Origin: https://b.hatena.ne.jp
を含むので例として使用している。
コード例1 (画像を取得できる)
<img src="https://b.st-hatena.com/images/users/gif/normal/00001.gif"> // OK
コード例2 (これは駄目)
fetch("https://b.st-hatena.com/images/users/gif/normal/00001.gif"); // CORS エラー
コード例3 (crossorigin 属性を付与すると駄目)
<img src="https://b.st-hatena.com/images/users/gif/normal/00001.gif" crossorigin="anonymous"> // CORS エラー
Chrome の Network タブを見てみると、コード1 の場合はリクエストヘッダーに Origin が含まれていないが、コード2,3 の場合は含まれている。
これは、MDN の Origin に関する記述から引用すると
There are some exceptions to the above rules; for example if a cross-origin GET or HEAD request is made in no-cors mode the Origin header will not be added.
ブラウザは、Origin ヘッダーを基本的には付与するものの、いくつもの例外が存在し、no-cors モードのリクエストには付与しないという。
no-cors モードは、すなわち img タグが(crossorigin 属性を付与しない限り)クロスオリジンでリクエストを行う場合に該当する。 Origin ヘッダーがなければ、たとえレスポンスに Access-Control-Allow-Origin ヘッダーが含まれていても許可されている Origin なのか判定できないから CORS 違反にはならないということだろうか?
ちなみに、fetch を利用して img タグのリクエストを再現すると以下になり、この場合は CORS 違反とはならない。
コード4
fetch("https://b.st-hatena.com/images/users/gif/normal/00001.gif", { mode: "no-cors", });
mode: no-cors の意味がやっと分かった気がする。
ちなみに、img タグを使われると画像配信側はクロスオリジンリクエストでレスポンスを必ず読み取られてしまうのか、というとそんなことはない。
Origin 解体新書の Origin をまたぐその他の仕様 にも記載があるが、サーバー側でリクエストのヘッダーに Origin が含まれているのか判定し、403 エラーを返す実装にすることで実現できる。
こうすると、コード1 のように crossorigin 属性が未付与の場合は Origin ヘッダーが含まれないので 403 エラーになるし、コード3 のように Origin ヘッダーを含めても許可されていない Origin は Access-Control-Allow-Origin に許容すべきオリジンを列挙してレスポンスに含めることでブラウザはレスポンスを読み取れない。
参考
https://stackoverflow.com/questions/47978252/how-img-tag-gets-content-over-cors-headers
flex item は幅を指定せずに margin: auto で縦横中央揃えできる
margin: auto
を使用した縦横中央揃えは要素自体に幅((max-)width, (max-height)
)の指定が必須と思っていた。
例えば、position: absolute
と組み合わせた以下の要素は親(absolute
の基準)に対して縦横中央揃えされるが
.test { background-color: aqua; position: absolute; top: 0; left: 0; right: 0; bottom: 0; margin: auto; max-height: 100px; max-width: 100px; }
これは max-width
と max-height
の指定がない場合は動作しない。
しかし、flex item (flex box の子要素) の場合はなぜか幅の指定がなくても縦横中央揃え可能になる。
.parent { display: flex; } .test { background-color: aqua; margin: auto; }
<div class="parent"> <div class="test">hoge</div> </div>
これは幅の指定の有無以外は、最初のコード例と同一になるので、親の大きさに合わせて縦横中央揃え可能になる。
こうすれば 500px の正方形の中で縦横中央揃えになる
.parent { display: flex; width: 500px; height: 500px; } .test { background-color: aqua; margin: auto; }
画面全体に対して縦横中央揃えする場合は、親自体を広げれば OK
.parent { display: flex; position: absolute; top: 0; left: 0; right: 0; bottom: 0; }
ちなみに、margin: auto
を使わずにこの指定でも問題ない
.parent { display: flex; justify-content: center; align-items: center; }
どちらがベストなのかは分からない。参考リンク↓
モブプログラミングのモブのときに意識していること
前提
- モブプログラミング歴 9 ヶ月程度
- 参加者は全員リモートワークで、最小2人、最大でも4人
- 自分がモブになるかドライバーになるかは事前に分からない(抽選)
- 何をモブプログラミングするかは事前にある程度分かっている
モブプログラミングをする前にやっていること
正直毎回予習しているわけではなく、ちょっと今日の開発は難しそうだなと思ったら準備する(場合もある)
- ドキュメントを軽く読んでおく
- 使用する言語やライブラリに慣れていない、使う予定の外部サービス(AWS, Google Analytics, Repro etc)に詳しくない場合
- 開発対象の既存コードを軽く読んでおく
- 該当箇所の既存コードを触ったことも見たこともない場合
- 大体の開発の進め方や議論して決めないといけないことをイメージしてみる
- 想定通りにならないことも多いが、なんとなく考えてみる
モブのときにやっていること
助ける
実装で悩んでいたら助ける
- 自分もすぐには分からないときは、ググって URL を共有する
- 例えば、言語、ライブラリのドキュメントや、既存コードで似たような修正を行ったプルリクとか。
先読みして助ける
- 何となくコードを書いていく流れが見えてきたら事前に障害になりそうな箇所についてググる、既存実装がないか調査するなど
- 例えば、文字列を数値に変換しないといけないことが明らかだったら、事前にググって型変換の良さげな方法を把握しておくとか。
進行する
悩みすぎて作業が止まってしまっていたら前に進める
- 命名、現段階では正解が分からない実装方針、個人の趣味の問題でしかないこと、誰かに質問した方が早いこと、議論の堂々巡りなど
- 大体は「とりあえず今はこれにして、後でまた考えましょう」とか「この人に後で聞きましょう」とか発言すると解消されることが多い
休憩をするように促す
- ドライバーをしていると、夢中になりすぎていたりするのでモブの人から休憩を提案する
- 疲労がコミュニケーションの軋轢になったりする
全員でやらなくてもいいことを切り分ける
- 何となく流れで単純な置換作業とかドキュメントの編集をしてしまうこともあるが、後で1人でできることなら後回しにしてモブプログラミングの効率を高める
質問する
ドライバーや他のモブの人と認識がズレている、何をしようとしているのか分からなくなったら質問する
- 分かったふりで進行してしまうとモブプログラミングをしている価値が下がってしまう
- 実は全員の考慮漏れで重要なことだったりもする(会話しながら考えていると、パターンの考慮漏れとかはけっこうある印象)
本筋と関係ないが、ショートカットキーや知らないコマンド、機能などがあったら質問する
- 流れ的に質問しにくい場合もあるが、けっこう学びになることがあるので質問してみると良い
- 逆にドライバーが自発的に説明するのは「いや、知ってるが...」みたいな空気になると嫌なので勇気がいると思う(相当マニアックなことなら良いが)
丁寧に会話する
口頭で説明できないことを無理に説明しない
- 図やコードで示したほうが早いことは、自分がドライバーでなくても一旦画面共有させてもらう等してコミュニケーションを効率化する
高圧的にならない
- 自分の方がよく理解している実装や分野の場合やコミュニケーションが上手くできないときに、もどかしい気持ちを感じたりするかもしれないが HRT を意識してコミュニケーションする。
記録する
- 考えたこと・学んだこと・やったことを書記として記録する
- モブプログラミングのログを残し、後から参照可能にする
- 決定事項だけでなく、思考や議論の過程とか、途中で悩んだこととかも書いておくと良い
- Scrapbox を使って全員が同時に読み書きできるようにしている
モブのときにやらない方がいいこと
- 画面を見てはいるが、一緒には考えていない、ついていけてない、同時に別の作業をしている
- モブプログラミングに参加している意義が薄くなる
- 音声を聞き取りにくい、画面の文字が見えにくい等環境面の我慢
- 遠慮せずに伝えたほうが全員のためになる。逆に指摘されたら素直に対応する。(音声の問題は自分でどうにもならないこともあるが)