ネイティブのハンドオフ
既存のレンダラーは、順序付けられたWebProjectionRequestメッセージをネイティブのスナップショットマネージャーのhandleへ転送してください。要求の検証、CSSからネイティブへの座標変換、キャッシュ画像のハンドオフ、複製の破棄をEngine内に集約できます。ブリッジはプラグイン自身のCapacitorまたはCordovaメソッドを使い続けます。Engineはどちらのフレームワークの呼び出しオブジェクトにも依存しません。
たとえば、レンダラーがツールバーボタンをまとめてネイティブへ更新し、各ボタングループに属するビューを把握しているとします。グループごとに座標変換と複製の破棄を再実装する代わりに、画像ハンドオフのメッセージをhandleへ転送します。グループのキャプチャ適格性と通常のレイアウトは、そのレンダラーに残します。Engineは、どの兄弟ビューを安全にまとめて隠せるかを推定できません。
ビューとスナップショットのライフサイクルAPIはメイン/UIスレッドで呼び出します。レンダラーから2つのコールバックを提供します。frames(ids, revision)は現在のキャプチャ可能な境界を、views(ids)は安全にまとめて非表示にできるネイティブビューの全体を返します。処理を利用できない場合は、空の境界またはnil / nullを返します。境界の単位は、iOSではWebViewに対する相対ポイント、AndroidではWebViewに対する相対物理ピクセルです。Engineは計測したIDが要求と完全に一致することを確認します。
snapshots.handle(request, in: webView,
frames: { ids, revision in renderer.measure(ids, at: revision) },
views: { ids in renderer.viewsAllowedToHide(ids) },
complete: reply)
snapshots.handle(request, activity.window, webView,
frames = { ids, revision -> renderer.measure(ids, revision) },
views = { ids -> renderer.viewsAllowedToHide(ids) },
complete = { result ->
result.fold(onSuccess = reply, onFailure = reject)
})
上のrendererとreplyは、プラグインの既存のレイアウト処理とブリッジ完了コールバックです。Androidでは、失敗したResultをブリッジの拒否コールバック(上のreject)へ渡します。Web側はその失敗を使い、画像を諦めて表示を再調整します。描画境界の失敗を成功として確認してはいけません。ジオメトリが安定する間、framesが繰り返し呼ばれることがあります。要求されたリビジョンとキャプチャ適格性を再確認し、レイアウトは変更しないでください。複数のコントロールが1つのネイティブコンテナを共有する場合、viewsは、未キャプチャのコントロールまで隠してしまう部分集合を拒否する必要があります。Engineはその関係を推定できません。ネイティブ操作の通知も、レンダラーの既存の仕組みを維持します。
coverは、それらのビューを隠す前に準備済みのピクセルを配置します。投影先のpartsはキャッシュ済みトークンと照合され、被覆と復元の両方に使われるため、準備済みサーフェスが移動しても古い位置は再利用されません。無効または利用できないハンドオフはshown: falseを返します。paintedとrestoredは対応する複製だけを破棄し、AndroidではWeb描画の準備完了を待ちます。releaseとresetは所有するリソースを破棄します。被覆や復元の経路でキャプチャを開始することはありません。
レンダラーは引き続き、restoreと受理された更新の確認応答の間に通常のネイティブ更新を行います。その更新の前に、iOSではrestoreControls()、AndroidではrestoreViews()を呼び、Engineが行った非表示変更だけを元に戻します。これは、任意のプラグインコンテンツを配置・再表示する指示ではありません。通常の可視性と配置の方針はレンダラーに残します。
スナップショットの直接操作
ハンドオフ中のネイティブ配置を連携側が所有する場合にのみ使います。NativeUIProjectionも、登録固有の配置方針と不透明ビューの方針で同じ操作を使います。要求をhandleへ転送する際、変換や複製の破棄を重複実装しないでください。
- CSSピクセルの投影先
partsを、iOSではwebView.bounds.width / viewportWidth、AndroidではwebView.width / viewportWidthで変換します。フレームをcoverとrestoreに渡します。coverのpartsがなければ、キャプチャ時の配置を維持します。どちらの操作も新しいピクセルをキャプチャしません。 transient: trueは、動く前面サーフェスを背景のcoveringTokenから分離します。ソースのサイズとスコープに対する相対位置が変わらない間、ピクセルを再利用します。固定スコープ内での移動はレイアウトを無効化します。- Web描画の準備完了後に移行時の複製を破棄します。iOSでは
retireCopy(token)、AndroidではretireCopyAfterWebDrawです。 - 戻す場合は
restoreを呼び、restoreControls()/restoreViews()でEngineの非表示変更を戻し、通常のネイティブレイアウトを適用します。ネイティブ更新が受理され、Web描画の準備が完了した後、retireCopyにentry: false/entry = falseを指定して復帰時の複製を破棄します。Androidではpaintedとrestoredをhandleへ転送すると、準備完了と拒否の処理を再利用できます。 release(token)でトークンを解放します。reset()は所有者の終了処理だけに使い、Androidのclose()でエンコーダーを破棄します。別のサーフェスのキャプチャをリセットしてはいけません。
キャプチャや配置がない場合は、レンダラーの通常のフォールバックを使います。ペイロードはWeb要求の契約を参照してください。
NativeUICoveredSnapshots.observeで操作の開始・終了をJSリスナーへ通知します。iOSではdrawHierarchy(in:afterScreenUpdates:)で可視ウィンドウをラスタライズし、クリップされたネイティブコンポーネントの背後も含めてキャプチャします。画面スナップショットビューは表示用の複製であり、ビットマップのソースには使いません。Liquid Glassのようなマテリアルでは、UIKitのラスタライズ結果が実際のコンポジターと異なる場合があります。プラグインが対応する背景で、実機の外観を検証してください。そのため、キャッシュの有効性にはレイアウトとプラグインの外観変更通知も含まれます。Engineは継続的にキャプチャせず、あらゆるレンダラーがキャプチャできるとも保証しません。
ネイティブのスクロール追従
Webのスクロールリスト内に置かれたネイティブコントロールは、そのままではリストの移動に合わせて新しい配置メッセージが必要です。レンダラーがすでにスクロールの調整を管理している場合にのみ、これらのバインディングを使います。一意に一致するiOSのoverflowスクロールビューに、ネイティブコンテンツを追従させられます。入れ子や曖昧なスクロールでは、誤ったスクロール所有者にコンテンツを取り付けるのではなく、通常のフォールバックを使ってください。
readScrollPlacement(element, owner, identify)は、変形されていない1つのoverflow所有者を計測します。createScrollBindings()は再利用を検証し、取得処理がACK待ちの間の移動を検出します。reuseはレイアウトの重複排除シグネチャに含めないでください。これはレイアウトではなく、確認応答の状態を表します。
iOSのNativeUIScrollBindings.replaceはソースを所有者ごとにまとめ、曖昧さなく一致するUIScrollViewだけにバインドします。update()はコンテンツを再構築せず、位置とクリッピングを適用します。NativeUIClippedViewはコンテンツ全体の寸法を維持しながら、表示ピクセルとヒットテストを制限します。
確立済みのバインディングがネイティブに拒否されると所有権を失い、同じ更新/ACK経路で新しく取得できます。新規取得が失敗した場合は、関連するレイアウトまたはスクロール終了イベントまでフォールバックに留まります。即時の再試行ループを追加したり、ユーザー操作を再実行したりしないでください。frameやpropsの変更で、確立済みの座標原点は再調整されません。
これは非公開のクラス名を使わず、WKWebView内部のoverflow階層を利用します。ビューの欠落・曖昧さ、入れ子のスクロール、ドキュメントのスクロール、未対応の変形、形状付きクリッピング、移動中で未確認の所有者にはバインドできません。UIScrollViewが存在するだけで対応しているとは判断しないでください。ネイティブビューはその内部で始まったジェスチャーを横取りする場合があります。その振り分けとSDKのアクセシビリティ動作は、引き続きレンダラー固有です。