iPhone のウィジェットのタップで、実機でだけ起きた3つの落とし穴
Sheet Widget のウィジェットには、タップで動く機能がいくつかあります。
- ウィジェットをタップすると、スプレッドシートやアプリが開く
- (Pro)セルをタップすると、その値をコピーできる
- (Pro)ウィジェットの更新ボタンで、すぐに最新の内容にする
iOS 17 からウィジェットにボタンを置けるようになり、こうした機能が作りやすくなりました。ただ、作ってみると、シミュレータや自動テストでは再現せず、実機のホーム画面でだけ起きる問題が3つありました。同じところでつまずく人がいるかもしれないので、まとめておきます。
1. ウィジェットから、クリップボードに書き込めない
「セルをタップしてコピー」は、最初、ウィジェットのボタン(App Intent)の処理の中で、そのままクリップボードに書き込む形で作りました。
UIPasteboard.general.string = value
ところが、実機ではこれがエラーも出さずに失敗します。処理は最後まで走るのに、クリップボードには何も入りません。調べたところ、ウィジェットの拡張機能からクリップボードに書き込めないのは、Apple にも報告されている既知の問題でした(Feedback ID: FB13636156)。
直し方:アプリを一瞬前に出してコピーする
ウィジェットの側では、どのセルが押されたか(行と列)だけをアプリに渡し、実際のコピーは、前面に出たアプリが行う形に変えました。
- ウィジェットのセルを、行と列を含んだ URL へのリンクにする
- タップすると Sheet Widget のアプリが開く
- アプリは、保存してあるシートの内容からその値を取り出してコピーする
- コピーしたあと、利用者が選んだ行き先(スプレッドシートを開く、など)に移る
アプリが前面に出ていれば、クリップボードには普通に書き込めます。
2. ボタンが、ウィジェットの長押しメニューを奪う
ウィジェット全体をタップできるようにするため、最初はウィジェット全体を、App Intent のボタンで包んでいました。
Button(intent: OpenAction()) {
GridView(...)
}
これを実機のホーム画面に置くと、ウィジェットを長押ししても「ウィジェットを編集」のメニューが出ず、先にボタンが反応してしまうようになりました。SwiftUI のボタンが長押しの操作まで受け取ってしまうためです。ウィジェットの設定(表示するシートの切り替えなど)ができなくなるので、致命的でした。
直し方:全体のタップは widgetURL、部分のタップは Link
ウィジェットのタップには、次のように使い分けるのが正解でした。
| タップしたい場所 | 使うもの |
|---|---|
| ウィジェット全体 | .widgetURL(...) |
| ウィジェットの一部(セルなど) | Link(destination:) |
| 小さなボタン(更新ボタンなど) | Button(intent:) のままで大丈夫 |
更新ボタンのように小さな領域なら、長押しのメニューとぶつからないので、ボタンのままにしています。
3. 一部の設定でだけ、タップしても反応しない場所ができた
「セルをタップしてコピー」をオンにしているときは、ウィジェット全体のタップ先(.widgetURL)を nil にしていました。セルのリンクを優先させたかったからです。
ところが、.widgetURL はウィジェット全体に効く1つの設定です。nil にすると、セル以外の場所(ヘッダー、フッター、空のセル)まで巻き添えで、タップしても何も起きなくなりました。
直し方:widgetURL は常に「行き先」を返す
.widgetURL は常に、利用者が選んだ行き先(スプレッドシートを開く、など)を返すようにしました。コピーするかどうかの判断は、URL を受け取ったアプリの側でまとめて行います。ウィジェットの側で分岐させないほうが、反応しない場所ができません。
教訓:タップまわりを触ったら、実機で全部押す
3つとも、XCTest やシミュレータでは見つけられず、実機のホーム画面に置いて、実際に指で押して初めて分かった問題でした。
それ以来、ウィジェットのタップまわりを変えたときは、次のことを実機で確認するようにしています。
- ウィジェットの全部の場所(ヘッダー、フッター、空のセル、値のあるセル、ボタン)をタップする
- 長押しで「ウィジェットを編集」が出るか
- 設定(コピーのオン・オフなど)を切り替えて、同じことを繰り返す
ウィジェットは「見るもの」から「触れるもの」になってきていますが、触れる部分には、アプリ本体とは違う制約がまだ多くあります。
Sheet Widget は App Store で公開しています。