結論
MainLayoutにリダイレクトを仕込む
以下詳細(コード)
クラス名、メソッド名等はテキトーに考えたものなので悪しからず
解説は最後に記載します
サービスを設定
public class Alarm
{
private Context _context;
public Alarm()
{
_context = Android.App.Application.Context;
}
public void Set()
{
// 10秒後に通知
var alarmTime = DateTime.Now.AddSeconds(10);
var intent = new Intent(_context, typeof(AlarmReceiver));
var pendingIntent = PendingIntent.GetBroadcast(_context, 0, intent, PendingIntentFlags.UpdateCurrent | PendingIntentFlags.Immutable)!;
var triggerTime = new DateTimeOffset(alarmTime.ToUniversalTime()).ToUnixTimeMilliseconds();
var alarmManager = (AlarmManager)_context.GetSystemService(Context.AlarmService)!;
alarmManager.SetExactAndAllowWhileIdle(AlarmType.RtcWakeup, triggerTime, pendingIntent);
}
}
レシーバー
[BroadcastReceiver(Enabled = true, Exported = true)]
public class AlarmReceiver : BroadcastReceiver
{
public override void OnReceive(Context? context, Intent? _)
{
if (context == null)
{
// 基本的に非null
throw new Exception();
}
var serviceIntent = new Intent(context, typeof(AlarmService));
context.StartForegroundService(serviceIntent);
}
}
サービス
[Service(ForegroundServiceType = ForegroundService.TypeMediaPlayback)]
public class AlarmService : Service
{
public override StartCommandResult OnStartCommand(Intent? _, StartCommandFlags flags, int startId)
{
// 通知チャンネルを作成
var channelId = "alarm";
var channel = new NotificationChannel(channelId, "Alarm Channel", NotificationImportance.Low);
(GetSystemService(NotificationService) as NotificationManager)!.CreateNotificationChannel(channel);
var pendingIntent = PendingIntent.GetActivity(this, 0, new Intent(this, typeof(AlarmActivity)), PendingIntentFlags.Immutable);
var notification = new Notification.Builder(this, channelId)
.SetContentTitle("TEST")
.SetContentText("タップしてアプリを開く")
.SetSmallIcon(Resource.Drawable.ic_clock_black_24dp)
.SetContentIntent(pendingIntent)
.Build();
StartForeground(1, notification);
return StartCommandResult.Sticky;
}
public override IBinder? OnBind(Intent? intent) => null;
}
アクティビティ
[Activity(Label = "AlarmActivity", Exported = true, LaunchMode = LaunchMode.SingleTop)]
public class AlarmActivity : Activity
{
protected override void OnCreate(Bundle? savedInstanceState)
{
base.OnCreate(savedInstanceState);
// 開きたいURLをセット
NavigationService.RedirectURL = "/test";
// アプリを起動
var launchIntent = new Intent(this, typeof(MainActivity));
launchIntent.AddFlags(ActivityFlags.ClearTop | ActivityFlags.NewTask);
StartActivity(launchIntent);
Finish();
}
}
ナビゲーションサービス
public static class NavigationService
{
public static string RedirectURL { get; set; } = "";
}
MainLayout
@inherits LayoutComponentBase
@inject NavigationManager NavigationManager
@Body
@code {
protected override void OnInitialized()
{
if (NavigationService.RedirectURL != "")
{
NavigationManager.NavigateTo(NavigationService.RedirectURL);
NavigationService.RedirectURL = "";
}
}
}
解説
関数の引数や働き、用語についての解説はしません
それぞれ調べてください
間違えていると思いましたら是非指摘ください
一連の流れ
ライフサイクル
MAUIBlazorのライフサイクル(というか画面表示までの流れ)はいじっていなければざっくり以下の通り
MainPage.xamlでページ作成 内部ブラウザを立ち上げる
↓
index.htmlの内容を内部ブラウザに表示
↓
<div id="app">Loading...</div>をRouteコンポーネントにより解決
↓
RouteコンポーネントがURL:"/"となっているRazorコンポーネントを表示する
↓
以下Blazorと同じ
これを頭に入れておいてください
通知の流れ
AlarmManagerが設定時刻になるとBroadcastを流す
↓
BroadcastをReceiverが受信し、サービスをForegroundServiceとして実行する
↓
サービスで通知を作成(チャンネルは一度作成すればいいので必要なければ別途初期化しておくのが吉)
※タップ時にActivityを実行するよう仕込んでおく
通知タップ時の流れ
仕込んでおいたActivityが実行される
↓
Activityで何かしらのStaticフィールドに遷移したいURLを設定
MainActivityを実行し画面起動
↓
URL:"/"のページを読み込んだ後、設定したURLに遷移
どうしてこの処理になったか
※一応ですが、MAUI Shellでの遷移はBlazor内での遷移とは別物なので方法から除外しています
調べるとMAUI側(MainPage.xaml.cs)でblazorWebView.TryDispatchAsync()を使えばいじれるとか見つかったんでそれを試してみたもののうまくいかず
MainLayoutでNavigationManagerを保存して、それを叩くような実装をしている人がいたので真似してみても通知からの起動では機能せず
そこで思い出したんですが、Blazor内ルーティングは画面表示の最後に行われています
なのでMainPage.xaml.csのOnAppeared()とか、ActivityのOnCreate()とかにルーティング仕込んでも、最後にRouteコンポーネントが"/"を表示しようとするので無意味だったんです
おとなしくMainLayoutにリダイレクト処理を入れることにしました
他にいい案あったら教えてください
蛇足
MAUIBlazor Hybridでアプリ作ろうとしているの、日本で俺だけですか?????
そんくらい日本語の情報がない
C#好きなので使いたいんですが、MAUIが割とゴミなのでなんとも言えないですね
ただBlazorは神 MAUIBlazor Hybridは神とゴミの同居
MAUIBlazor Hybridを使うならある程度英語に耐性ないと苦しいですね
参考にしたの大体英語の記事か、外人ニキのYoutubeで、日本語であるのは「触ってみた」くらいのものしかない、、、
(あとChatGPTが嘘しかつかない 参考ドキュメントが少ないからか、かなりハルシネーションしてくる、、、)
ので今後も詰まったところはこんな感じで記事にしていきます
MAUIBlazor使ってるよって方はぜひフォローしてください