.NET 9 の HybridWebView を試す
.NET 9 Preview 7 で HybridWebView が追加された。
Xamarin.Forms 時代にも CustomRenderer の実装例として挙げられていた HybridWebView だが、MAUI Control として提供されるようになった。
HybridWebView に自分はかなり期待をしている。
というのも、私は MAUI の View の作成にメインで使われている XAML があまり得意ではなく、その代替策(?)としてある Blazor もあまり得意ではない(VSCode での補完だったりが絶望的なのもあり)。
しかしながら、React などのように JSX を使用して View を作ることはある程度得意であるため、なるべくそういう方法で出来ないかと探していたためである。
試した結果のリポジトリがこちら。
試してみた感じかなり良かった。
この前身(?)となるプロジェクトの Eilon/MauiHybridWebView では戻り値を受け取れるなどの機能もあり、それに対して公式が追いついていないというか、なんというかという箇所はあるが今でも十分使えると思う。
現状動かす際、macOS 15 を使用している場合は 1点注意が必要で、以下の Workaround が必要。
#if MACCATALYST
// https://github.com/dotnet/maui/issues/23390#issuecomment-2202295194
var handlerType = typeof(Microsoft.Maui.Handlers.HybridWebViewHandler);
var field = handlerType.GetField("AppOriginUri", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic) ?? throw new Exception("AppOriginUri field not found");
field.SetValue(null, new Uri("app://localhost/"));
#endif
macOS 15 には Safari 18 がインストールされていて、0.0.0.0 Day
の対策されたものであるというのが恐らくの原因だろうけれども、Safari 18 の入った macOS 14 では動くという…
React アプリケーションと動かす際は、以下のような CustomHooks を用意すると便利だった。
.NET に対して通信を行う箇所を、外部 API を呼び出すみたいな形でラップしてあげることである程度使い勝手は向上した。
import { useCallback } from "react";
type HybridWebViewType = {
/**
* Sends a message to .NET using the built in
* @param {string} message Message to send.
*/
SendRawMessage: (message: string) => void;
};
declare global {
interface Window {
HybridWebView: HybridWebViewType;
}
interface WindowEventMap {
HybridWebViewMessageReceived: CustomEvent<{ message: string }>;
}
}
export const useHybridWebView = () => {
const sendInvokeMessageToDotNetAsync = useCallback(
(methodName: string, paramValues: any[]) => {
const timestamp = performance.now().toString();
window.HybridWebView.SendRawMessage(
JSON.stringify({ timestamp, methodName, paramValues })
);
return new Promise((resolve) => {
const cb: Parameters<
typeof addEventListener<"HybridWebViewMessageReceived">
>[1] = (ev) => {
const parsedMessage = JSON.parse(ev.detail.message);
if (
parsedMessage.timestamp === timestamp &&
parsedMessage.methodName === methodName
) {
window.removeEventListener("HybridWebViewMessageReceived", cb);
resolve(parsedMessage.value);
}
};
window.addEventListener("HybridWebViewMessageReceived", cb);
});
},
[]
);
return {
sendInvokeMessageToDotNetAsync,
};
};
HybridWebView で現在提供されている SendRawMessage は戻り値を受け取れないのだが、SendRawMessage でメッセージを送る際に messageId の様なものを同時に送って、EventListner で待ち受けて非同期で処理できるように工夫している。
この件だが、本日リリースされたrc2では不要になっている
というのも、コンテンツを0.0.0.1でホスティングするようにControlが変更されたためである
rc2で更にmacOSで、Safari経由でのDebugの改良が行われた
これもWorkaroundが必須だったのが不要になった
現在は非同期で戻り値を受け取るために自分でEventListenerをうまく使うようにしているが、これも今後のアップデートで不要になりそうだ
rc2がリリースされたため、これが.NET 9に入るのは難しそうではあるが、可能になったらかなり便利ではある
本日から開催の.NET Conf 2024でHybridWebViewの紹介があったので、リンクを載せておく
.NET 9正式リリースに伴い、前のコメントで不要になりそうだとコメントしていた箇所が解消されているため、もう少し触ってから記事にしよう。