UISearchBarのデフォルトの背景色は `UIColor.tertiarySystemFill`

Use system fill colors for items situated on top of an existing background color. System fill colors incorporate transparency to allow the background color to show through.

Use this color to fill large shapes, such as input fields, search bars, or buttons.

と説明されているとおりだった。

ライトでの cgColor の出力はこんな感じ:

<CGColor 0x60000260e1c0> [<CGColorSpace 0x60000260cf00> (kCGColorSpaceICCBased; kCGColorSpaceModelRGB; sRGB IEC61966-2.1; extended range)] ( 0.462745 0.462745 0.501961 0.12 )

UIButton.Configuration.Sizeの各サイズごとのデフォルト状態での高さ

iOS 16.1シミュレーターで確認してみた。

UIButton.Configuration.Size

@2x @3x
UIButton.Configuration.Size.large 50.5 50.33…
UIButton.Configuration.Size.medium 34.5 34.33…
UIButton.Configuration.Size.small 28 28
UIButton.Configuration.Size.mini 28 28

特別にHuman Interface Guidelinesの44x44ポイントのヒットターゲットが意識されている・遵守するようになっているわけではないのか。

Buttons - Menus and actions - Components - Human Interface Guidelines - Design - Apple Developer

Make buttons easy for people to choose. On a touchscreen, buttons need a hit target of at least 44x44 points to accommodate a fingertip.

iOSシミュレーター・Androidエミュレーターにアプリをインストールだけする(起動までしない)方法

なぜ

アプリの初回起動時専用の特別な処理や画面遷移を行うケースで、そのデバッグ実行・動作確認をするため。

iOS

まずインストールするためのアプリは Build For Running でビルドしておく。次にシミュレーターを起動しておいて

xcrun simctl install booted <~~.appのパス>

のコマンドを実行する。

もしくは、シミュレーターのウィンドウに ~~.app をFinderからドラッグ&ドロップする。

Xcodeのスキーム設定の Wait for the executable to be launched が使えるのでは、と一瞬考える。しかしこれはシミュレーターにインストール済みのアプリには使えるのだが、まだインストールされていないアプリの場合は、アプリのインストールまではやってくれないので、ただ待つだけ(何も起きない)状態になる。ので、別途自分でインストールしてあげる必要がある。

UserDefaultsやKeychainも含めてまっさらな初回起動状態の再現のために、シミュレーターのメニューの Device -> Erase All Content and Settings… も便利。

Android

エミュレーターを起動しておいて

gradlew installDevelopDebug

のコマンドを実行する。DevelopDebug の部分は使いたいbuild variantを指定する。こちらはエミュレーターではなく実機接続でも動作する。

iOSシミュレーター同様に、エミュレーターのウィンドウにapkファイルをドラッグ&ドロップでもインストールできる。

Mockolo 1.7.0のビルド済みバイナリがarm64にしか対応していない

https://github.com/uber/mockolo/releases/download/1.7.0/mockolo.tar.gz に含まれる mockolo バイナリがarm64アーキテクチャーにしか対応していなかった。これだとAppleシリコンMacでは実行できるが、Intel Macでは実行できない。

$ file mockolo
mockolo: Mach-O 64-bit executable arm64

その前はどうかと思って1.6.3を確認してみたら、そちらはx86_64だけだった。これは本当はx86_64でもarm64でも実行できるユニバーサルバイナリになっていてほしい。

ということで修正PRを出してみている。SwiftPMでは swift build の引数に --arch arm64 --arch x86_64 を足すだけでユニバーサルバイナリにできるので、それをやっただけです。

github.com

追記

このPRを含む1.7.1がリリースされていました。Intel Macの方もAppleシリコンMacの方もどうぞご利用ください。

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向けのバイナリではスクリプトがコード中に埋め込まれていたのですね。めでたしめでたし。

App Storeの定期購読・無料トライアルの基準タイムゾーンはUTC

App Store Connectのドキュメント(ヘルプページ)にはこうあります:

自動更新登録は、1 か月間の日数ごとではなく、最初の購入の暦日と同じ日に更新します。たとえば、カスタマーが 1 か月の無料トライアルを 1 月 7 日に開始する場合、トライアルが終了するのは 2 月 7 日です。翌月に同じ日が存在しない日に 1 か月のトライアルを開始した場合、トライアルが終了するのは翌月の末日ですが、利用可能になると元の日付に戻ります。たとえば、カスタマーが 1 月 30 日に登録すると、次の更新日は、2 月 28 日 (閏年の場合は 2 月 29 日) で、その次は 3 月 30 日になります。

これだけだと「そうですね」となるのですが、仕事で見かけた事例によると、どうも日時はUTCタイムゾーンを基準としているようです。日本時間などユーザーのローカルタイムゾーン基準でないことで、次のようなややこしいことが発生し得ます。

  1. 日本時間の3月1日 午前9時(UTC 3月1日 午前0時)に無料トライアルを開始
    • 無料トライアルの終了日(課金開始日)は4月1日
  2. 日本時間の3月1日 午前8時(UTC 2月28日 午後11時)に無料トライアルを開始
    • 無料トライアルの終了日(課金開始日)は3月28日で、4月1日ではない!

日本時間では同じ3月1日に無料トライアルを開始しても、たった1時間の違いで無料トライアルの期間が3日間も短くなってしまいます。

ということで、開発者としてユーザーからの問い合わせへの返答にも、ユーザーとして無料トライアルを最大限活用するのにも使える豆知識でした。

和暦と改元とうるう年が組み合わさったバグの思い出

あけましておめでとうございます。新年一発目の投稿は2019年の思い出です。

ということで本年もよろしくお願いします 🙏