Silent Audio in iOS with Cordova

I built my game with Phaser 3.55.2. I’ve read many threads on here and on Stack Overflow about issues with audio in iOS using Cordova or Capacitor. I noticed most of these are a couple years old at this point. I’ve also researched it with ChatGPT.

Does anyone know a definitive way to get the audio to work with Phaser’s audio system without switching to the Cordova media plugin? For me, sound works everywhere but in my Cordova app for iOS (it works in Safari). I’m using Ionic WebView. With webAudio enabled, the app won’t load any audio files, so I went with HTML5 audio. I’m using mp3’s. Attached is the class I wrote to manage my soundtrack and effects. In my preload, I simply run:

soundManager = new SoundManager(this);
SoundManager.js (4.7 KB)

Below is what I’ve done\tried. I’m wondering:

  • Am I missing something really dumb to get it working?
  • Do I have to redo the sound system with the media plugin for Cordova?
  • Does this simply not work for some reason I missed?

config.xml

<preference name=AllowInlineMediaPlayback value=true />
<preference name="AllowMixedContent" value="true" />
<preference name=MediaTypesRequiringUserActionForPlayback value=none />
<config-file parent="UIBackgroundModes" target="*-Info.plist">
	<array>
		<string>audio</string>
	</array>
</config-file>

JavaScript

audio: {
	disableWebAudio: true
}

new ((window).AudioContext || (window).webkitAudioContext)()

this.playButton = this.add.text(98, 138, 'START', this.styles);		
this.playButton.setInteractive().on('pointerdown', function(){
	that.scene.stop();
	**that.sound.unlock();**  // I read this is not needed for HTML5 audio.
			
	that.scene.launch('Intermission', {
		color:that.characterColor,
			world:gameData.get('world'),
			character:gameData.get('character'),
			mode:(localStorage.getItem('mode') ? localStorage.getItem('mode') : 'Nice')
		});
 	});
});

I switched back to webAudio and I found that the sound is unlocked properly, and the state is running. The issue is that the Phaser load function is not loading anything. The audio cache is empty. It seems it’s getting blocked somehow.

If anyone runs into this issue, I found that Ionic Webview wasn’t loading mp3 audio files. In fact, I don’t think it was even trying as all the headers were blank and it wouldn’t fire any kind of error callback or throw any error. There must be a permissions issue on iOS, but nothing I tried fixed it.

I found that the app could load json files though, so I encoded all my sound files as base64, embedded them in a JSON object in separate files and loaded those with AJAX. Then, I used a Blob to convert the audio data to a URL dynamically, and I passed that to Phaser’s audio.load() method. I only had to add a few lines to my code for this, and it works:

$.each(sounds.fx, function(key, value){
	$.get(value.replace('mp3', 'json'), function(response){
		that.scene.load.audio(
			key, 
			URL.createObjectURL(that.convert(response.sound))
		);
	});
});

convert(base64) {
	const binaryString = atob(base64);
	const byteArray = new Uint8Array(binaryString.length);
	for (let i = 0; i < binaryString.length; i++) {
		byteArray[i] = binaryString.charCodeAt(i); // Convert each character to its char code
	}
	return new Blob([byteArray], { type: 'audio/mpeg' });
}

Important Note: After posting this, I found out you should use this.load.json, not get or fetch commands.

This is my Content Security Policy

<meta http-equiv="Content-Security-Policy" content="
    default-src 'self' data: blob:;
    script-src 'self' 'unsafe-inline' 'unsafe-eval';
    style-src 'self' 'unsafe-inline';
    connect-src 'self' blob: data: ionic:;
    media-src 'self' blob: data:;
">

Also, use webAudio:true, not HTML5.