potatotips #77で「RenovateによるiOSライブラリーの自動更新」という発表をしました&いくつかの補足

発表資料はこちらです 👇

発表の中では時間の都合で触れられなかったところをいくつか補足しようと思います。

CocoaPodsでRealmを使っているとPodfile.lockが更新できない件

github.com

Renovateの実行環境はDockerコンテナの中のUbuntuです。Renovateは Podfile を書き換えた後に pod install を実行してPodfile.lock を更新します。CocoaPodsはLinuxで動くのか?と思われるかもしれませんが、pod gem(や依存の xcodeproj)もLinuxで問題なく動作するようです。ほとんどのライブラリーは問題ないのですが、Realmのpodspecには少し特殊なところがあります。

https://github.com/realm/realm-swift/blob/8c1cbf124c5025da9220595e7764059963065891/Realm.podspec#L110

  s.prepare_command         = 'sh scripts/setup-cocoapods.sh'

podspecのprepare_commandスクリプトを実行しています。そのスクリプトではrealm-coreをダウンロードしているのですが、その先頭でset -euo pipefailとしており、bashではなくshだとエラーになってしまいます。

build.sh: 13: set: Illegal option -o pipefail

さらにここをbashで実行したとしてもスクリプト内部でxcode-selectコマンドが使われているので、どちらにせよ詰んでしまいます。

ここで我々ができることは、発表のSwiftPMの箇所で「Package.resolvedの更新に非対応」でも触れた

  • PRに自分で追いコミットをするか、もしくは
  • CIで(例えばGitHub Actionsで)更新するワークフローを用意する

という感じになりそうです。

on:
  pull_request:
    paths:
      - Podfile
jobs:
  precheck:
    runs-on: ubuntu-latest
    outputs:
      files_changed: ${{ steps.file_changes.outputs.files }}
    steps:
      - uses: actions/checkout@v3
      - id: file_changes
        uses: trilom/file-changes-action@v1.2.4
  update:
    runs-on: macos-latest
    needs: precheck
    if: contains(fromJson(needs.precheck.outputs.files_changed), 'Podfile.lock') == false
    steps:
      - ...

CocoaPodsとXcodeGenを併用しているとPodfile.lockが更新できない件

XcodeGenを使用していると、通常生成したXcodeプロジェクトはリポジトリにコミットせず、CIでも初期セットアップでコマンドを実行してXcodeプロジェクトを生成すると思います。これがRenovateでは困ったことになります。Renovateの実行時に任意の初期化処理を挟むことができず(そもそも実行環境にXcodeGenも存在しない)、Xcodeプロジェクトが存在しないままだとpod installの実行に失敗してしまうためです。

これを回避する手段として、CocoaPodsの:integrate_targetsという設定を使用できます。Podfileのルートではinstall!というオプションを設定することができます。その引数に :integrate_targets => false と指定することで、Xcodeプロジェクトへの組み込みステップが省略されるため、Xcodeプロジェクトがなくても pod install を実行できるようになります。

この設定をRenovateでの実行時だけ有効にするように、以下のようにハックします。

is_running_in_renovate = ENV['HOME'] == '/home/ubuntu'
if is_running_in_renovate
  # Renovateでの実行時にはXcodeGenが実行できず、xcodeprojが存在しないので `:integrate_targets => false` とする。
  install! 'cocoapods', :integrate_targets => false
else
  install! 'cocoapods'
end

ただこの設定には注意点があり、:integrate_targets => falseだとアプリが使用しているSwiftのバージョンをXcodeプロジェクトから抜き出すことできなくなり、ライブラリー側のビルド設定のSWIFT_VERSIONが設定されなくなってしまいます。

これも回避策があり、Podfile内の各ターゲットで current_target_definition.swift_version = '5.0' と明示的に定義してしまえば問題ありません。

target 'FooBarApp' do
  # https://github.com/CocoaPods/CocoaPods/issues/8653#issuecomment-488767262
  current_target_definition.swift_version = '5.0'
  ...
end

おわりに

モバイルアプリ開発でもどんどんRenovateを活用していきたいですね!!

その他の方の発表資料はconnpassのページからどうぞ!

actions/checkoutのアップデートで、gitのsafe.directoryの件が対策されていました

先週盛り上がっていた、gitのCVE-2022-24765に対する修正でreviewdogなど一部のGitHub Actions(Dockerコンテナのアクション)が動かなくなっていた問題ですが

actions/checkout側でチェックアウトしたディレクトリをsafe.directoryにセットしてくれる対策が入っていました。

Issue:

リリース:

set-safe-directoryというinputで制御できるようにもなっています。デフォルトで有効ですが、

- uses: actions/checkout@v3
  with:
    set-safe-directory: false

として無効にすることもできます。

これで安心して使えそうですね。こちらからは以上です。

GitHub ActionsのVirtual Environmentの更新でnpmのバージョンが変わったことでreviewdog/action-eslintが動かなくなったという面白事例

React Nativeのアップデートのコツはビルドシステムやパッケージマネージャーの気持ちになること

半分ネタで半分本気です。

達と仲良くなり(詳しくなり)、あとはReact Native Upgrade Helperで差分をチェックすれば大体いけるはず。Let's upgrade!

AndroidのNotification Channels is 通知チャンネル OR 通知チャネル

Android O(Android 8.0)から追加されたNotification Channelsですが、これの日本語訳がぶれていてどっちで会話すればいいのか困っています。

FirebaseのSwiftPM対応に伴ってGoogle Tag ManagerもSwiftPMでインストールできるようになっていた

iOS(ないしAppleプラットフォーム全般)のFirebaseといえばこれまでインストール方法はCocoaPodsが基本だったが、バージョン8.0.0からSwiftPMでもインストールできるようになっている。

さて、Firebase Analyticsと組み合わせて使えるツールとしてアプリ向けのGoogle Tag Manager(以下GTM)もあるのだが、これもSwiftPMで扱えるのか。8.0.0がリリースされた直後の2021年5月時点ではサポートされていなかったのだが、2021年8月からひっそりとサポートされるようになっていた。

ということでGTMのSwift Packageは https://github.com/googleanalytics/google-tag-manager-ios-sdk で公開されているので、これを使えば良いことがわかった。


ところでGTMのSwift Packageはバイナリとしては https://dl.google.com/firebase/ios/tagmanager/swiftpm/7.4.0/GoogleTagManager.zip というzipを参照していて、これはCocoaPods向けの https://dl.google.com/firebase/ios/tagmanager/405c0e6ab8f653b7/GoogleTagManager-7.4.0.tar.gz とは別物になっている。中身を確認してみたところ、CocoaPods向けバイナリ(xcframework)では TagManagerResources.bundle というバンドルがxcframeworkのResourcesに含まれていて、podspecでもそのバンドルがアプリに追加されるようになっている。

https://github.com/CocoaPods/Specs/blob/a26c0002e6e8fe7fcd3059ec699d1f2e05f71400/Specs/9/5/6/GoogleTagManager/7.4.0/GoogleTagManager.podspec.json#L29-L31

TagManagerResources.bundle の中身は Info.plist を除くと TAGRuntime.js.dat というファイルが1つだけだった。SwiftPM向けのxcframeworkを確認してみると、そこにはResourcesも TagManagerResources.bundleTAGRuntime.js.dat も見当たらない。これはちゃんと動くのだろうかと不安になったが、Mach-O Executables · objc.io に書かれている手段で、otool を使って中身をチェックしてみた。

$ xcrun otool -v -s __TEXT __cstring -arch arm64 GoogleTagManager.xcframework/ios-arm64_armv7/GoogleTagManager.framework/GoogleTagManager | grep TAGRuntime
0000000000001857  T@"TAGRuntime",&,N,V_runtime
GoogleTagManager.xcframework/ios-arm64_armv7/GoogleTagManager.framework/GoogleTagManager(TAGRuntime+Script.o):
GoogleTagManager.xcframework/ios-arm64_armv7/GoogleTagManager.framework/GoogleTagManager(TAGRuntime.o):

TAGRuntime+Script.o というのがいかにも怪しい(それっぽい)のでセクションの中身も見てみる。

$ xcrun otool -v -s __TEXT __cstring -arch arm64 GoogleTagManager.xcframework/ios-arm64_armv7/GoogleTagManager.framework/GoogleTagManager | grep TAGRuntime+Script -A2
GoogleTagManager.xcframework/ios-arm64_armv7/GoogleTagManager.framework/GoogleTagManager(TAGRuntime+Script.o):
Contents of (__TEXT,__cstring) section
000000000000000c  \nvar aa,ba=this,h=function(a,b){var c=a.split("."),d=ba;c[0]in d||!d.execScript||d.execScript...

ということで、いかにもJavaScriptらしきものが確認できて、この内容は TAGRuntime.js.dat と合致していた。SwiftPM向けのバイナリではスクリプトがコード中に埋め込まれていたのですね。めでたしめでたし。

チームでのスマホアプリエンジニア採用のために求人票について考えていた

こんにちは。近頃はSwiftUIでの新機能開発に勤しんでいる id:ikesyo です。

そんなこんなで自分が所属しているはてなマンガアプリチームでは最近、iOSエンジニア・Androidエンジニアを積極採用しようと動き出しています。その中でまず求人票の内容を検討していました。これまでしたことがなかったけれど求人票を考えるのは意外と面白くて、

  • 要件の洗い出しを通じて、これは現在のチームメンバーも含めたスキルマップについて考えているのだなと思ったり、
  • チームの様子を伝えようとチームのカルチャーについて考えたり、
  • このチーム・はてなで働くメリットはなんだろうと考えたり、

日々のタスクに向かい合っているだけだと忘れがちなことに目を向ける良い機会になっています。

この新たな求人票・採用ポジションはそのうちお目見えするはずですが、SwiftUI・Jetpack ComposeとGraphQLをガシガシ使った開発に取り組んでいるので、

  • 漫画が好き
  • 宣言的UI
  • GraphQL
  • マルチモジュール化

といったキーワードにビビッとくる方はTwitterのDMなどで是非ご連絡ください。まずはカジュアル面談しましょう!