MAUI中WebView音频跳转/后台播放中断问题(Android)
MAUI Android WebView音频后台播放问题解决
问题描述
在MAUI项目中使用WebView播放音频,iOS平台能正常在跳转页面、切换应用或锁屏时持续播放,但Android端会出现音频暂停的情况。补充说明:音频在弹窗窗口中播放,关闭弹窗后音频可正常播放,但跳转至其他ContentPage时音频停止。
现有代码
XAML布局
<WebView x:Name="audio_webview" BackgroundColor="Transparent" Navigated="OnWebViewNavigated" HorizontalOptions="FillAndExpand" VerticalOptions="CenterAndExpand" > <WebView.HeightRequest> <OnIdiom x:TypeArguments="x:Double"> <OnIdiom.Phone>80</OnIdiom.Phone> <OnIdiom.Tablet>120</OnIdiom.Tablet> <OnIdiom.Desktop>80</OnIdiom.Desktop> </OnIdiom> </WebView.HeightRequest> <WebView.WidthRequest> <OnIdiom x:TypeArguments="x:Double"> <OnIdiom.Phone>420</OnIdiom.Phone> <OnIdiom.Tablet>630</OnIdiom.Tablet> <OnIdiom.Desktop>420</OnIdiom.Desktop> </OnIdiom> </WebView.WidthRequest> </WebView>
C#逻辑
public DailyAudioPopUpPage(string audioUrl) { InitializeComponent(); LoadAudio(audioUrl); } private void LoadAudio(string audioUrl) { var html = $@" <html> <body style='margin:0; background-color: transparent; display:flex; justify-content:center; align-items:center; height:100%;'> <audio controls autoplay style='width:90%;'> <source src='{audioUrl}' type='audio/mpeg'> Your browser does not support the audio element. </audio> </body> </html>"; audio_webview.Source = new HtmlWebViewSource { Html = html }; }
跳转页面时的日志输出
11:04:37:012 [AAudio] AAudioStream_requestStop(s#1) called 11:04:37:012 [AAudio] AAudioStream_close(s#1) called --------------- 11:04:37:012 [AAudioStream] setState(s#1) from 10 to 11 11:04:37:012 [AudioTrack] stop(portId:2774, sessionId:48889): 0xb400006eb01c3f40, prior state:STATE_STOPPED 11:04:37:012 [AudioTrackShared] this(0xb400006e500b8550), mCblk(0x6d7fcdc000), front(311736), mIsOut 1, interrupt() FUTEX_WAKE 11:04:37:012 [AudioTrack] requestExitAndWait start 11:04:37:012 [AudioTrack] requestExitAndWait end 11:04:37:012 [AudioTrack] stopAndJoinCallbacks(2774) done 11:04:37:012 [AudioTrack] ~AudioTrack(2774): 0xb400006eb01c3f40 11:04:37:072 [AudioTrack] getpackName client name com.companyname.appname(24146) 11:04:37:072 [AudioTrack] stop(portId:2774, sessionId:48889): 0xb400006eb01c3f40, prior state:STATE_STOPPED 11:04:37:072 [AudioTrack] stopAndJoinCallbacks(2774) done 11:04:37:072 [AAudioStream] setState(s#1) from 11 to 12 11:04:37:072 [AAudioStream] ~AudioStream(s#1) mPlayerBase strongCount = 2 11:04:37:072 [AAudio] AAudioStream_close(s#1) returned 0 ---------
日志说明:这段日志显示Android系统主动停止并关闭了AAudio音频流,原因是原页面跳转后WebView被系统回收,关联的音频资源也被释放。
解决方案
1. 配置Android权限与前台服务声明
在Android项目的AndroidManifest.xml中添加以下配置,声明前台服务权限和媒体播放服务:
<!-- 添加权限 --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <!-- 在application标签内添加服务声明 --> <application ...> <service android:name=".AudioPlaybackService" android:foregroundServiceType="mediaPlayback" /> </application>
2. 实现Android原生前台服务
在Android项目中创建AudioPlaybackService.cs,用于维持音频播放的前台状态,避免系统回收资源:
using Android.App; using Android.Content; using Android.Media; using Android.OS; using AndroidX.Core.App; namespace YourAppNamespace.Droid; [Service(ForegroundServiceType = Android.Content.PM.ForegroundService.TypeMediaPlayback)] public class AudioPlaybackService : Service, AudioManager.IOnAudioFocusChangeListener { private AudioManager _audioManager; private const int NotificationId = 1001; public override void OnCreate() { base.OnCreate(); _audioManager = (AudioManager)GetSystemService(AudioService); } public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId) { // 请求音频焦点,确保播放优先级 var focusResult = _audioManager.RequestAudioFocus(this, Stream.Music, AudioFocus.Gain); if (focusResult != AudioFocusRequest.Granted) { StopSelf(); return StartCommandResult.NotSticky; } // 创建前台通知(Android 8.0+必须) var notificationIntent = new Intent(this, typeof(MainActivity)); var pendingIntent = PendingIntent.GetActivity(this, 0, notificationIntent, PendingIntentFlags.Immutable); var notification = new NotificationCompat.Builder(this, "audio_playback_channel") .SetContentTitle("音频播放中") .SetContentText("正在后台播放音频") .SetSmallIcon(Resource.Drawable.ic_notification) // 替换为你的通知图标 .SetContentIntent(pendingIntent) .SetPriority(NotificationCompat.PriorityLow) .Build(); // 创建通知渠道 if (Build.VERSION.SdkInt >= BuildVersionCodes.O) { var channel = new NotificationChannel("audio_playback_channel", "音频播放", NotificationImportance.Low); var notificationManager = (NotificationManager)GetSystemService(NotificationService); notificationManager.CreateNotificationChannel(channel); } // 启动前台服务 StartForeground(NotificationId, notification); return StartCommandResult.Sticky; } public override void OnDestroy() { _audioManager.AbandonAudioFocus(this); base.OnDestroy(); } public override IBinder OnBind(Intent intent) => null; public void OnAudioFocusChange(AudioFocus focusChange) { // 处理音频焦点变化,比如来电时暂停播放 if (focusChange == AudioFocus.LossTransient || focusChange == AudioFocus.LossTransientCanDuck) { // 可在此处调用WebView的JS暂停音频 } else if (focusChange == AudioFocus.Gain) { // 恢复播放 } } }
3. MAUI层控制服务启停
在MAUI的音频播放逻辑中,添加平台特定代码来启动/停止前台服务:
using Microsoft.Maui.ApplicationModel; // 启动后台音频服务 private void StartBackgroundAudioService() { #if ANDROID var context = Android.App.Application.Context; var serviceIntent = new Android.Content.Intent(context, typeof(YourAppNamespace.Droid.AudioPlaybackService)); if (Build.VERSION.SdkInt >= BuildVersionCodes.O) { context.StartForegroundService(serviceIntent); } else { context.StartService(serviceIntent); } #endif } // 停止后台音频服务 private void StopBackgroundAudioService() { #if ANDROID var context = Android.App.Application.Context; var serviceIntent = new Android.Content.Intent(context, typeof(YourAppNamespace.Droid.AudioPlaybackService)); context.StopService(serviceIntent); #endif }
调用时机:在音频开始播放时调用StartBackgroundAudioService(),在音频停止或应用退出时调用StopBackgroundAudioService()。
4. 避免WebView被页面跳转销毁
跳转到其他ContentPage时,原页面可能被导航栈销毁,导致WebView回收。可以通过以下两种方式处理:
- 启用页面缓存:在App.xaml.cs中配置导航页面的缓存模式:
MainPage = new NavigationPage(new MainPage()) { NavigationCacheMode = NavigationCacheMode.Enabled };
- 保留导航栈中的原页面:跳转时设置
animated为true(默认),确保原页面保留在栈中:
await Navigation.PushAsync(new TargetContentPage(), true);
5. 优化WebView的音频播放属性
修改HTML中的audio标签,添加playsinline属性确保Android端播放兼容性,并在WebView加载完成后手动触发播放(Android限制自动播放需要用户交互):
<audio controls autoplay playsinline webkit-playsinline style='width:90%;' id='audioPlayer'> <source src='{audioUrl}' type='audio/mpeg'> Your browser does not support the audio element. </audio>
在WebView的Navigated事件中手动调用播放:
private void OnWebViewNavigated(object sender, WebNavigatedEventArgs e) { _ = audio_webview.EvaluateJavaScriptAsync("document.getElementById('audioPlayer').play();"); }
内容的提问来源于stack exchange,提问作者Matthew Pans
相关产品推荐
相关产品推荐

