title: How to play audio in WKWebView?
body: <p>I'm making an iOS app to wrap my javascript game. On mobile safari it works fine because after I play a sound in ontouchstart, then I'm allowed to play any audio whenever I want, and I can set their volume too.</p>
  
  <p>Problem 1: In a WKWebView I can only play the specific sounds that I played in ontouchstart, not the rest. So I'm playing every single audio in my game on the first tap. It sounds really bad. Otherwise in the javascript on audio.play() I get
  <code>Unhandled Promise Rejection: NotAllowedError: The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission.</code></p>
  
  <p>Problem 2: I also can't lower the volume of sounds in a WKWebView. If I set myAudio.volume=.5 it's instantly 1 again. Which means the user has to actually hear them, in order for them to get to readyState=4</p>
  
  <p>Any good solution or hack? Right now I'm playing every single sound on the first tap, and everything is full volume.</p>
  
  <pre><code>&lt;html&gt;
      &lt;body style='bakcground:#DDD;height:333px'&gt;
          &lt;div id=debug style='font-size:20px' onclick="playSound(myAudio)"&gt;
              Debug&lt;br /&gt;
              Tap here to play the sound.&lt;br /&gt;
          &lt;/div&gt;
          &lt;script&gt;
              var context = new webkitAudioContext()
              var myAudio = new Audio("sound/upgrade.wav")
              myAudio.addEventListener('canplaythrough', function(){log('canplaythrough1')}, false)
              var myAudio2 = new Audio("sound/dragon.wav")
              myAudio2.addEventListener('canplaythrough', function(){log('canplaythrough2')}, false)
  
              function playSound(sound)
              {
                  log("playSound() readyState="+sound.readyState)
                  try{
                      sound.play()
                      context.resume().then(() =&gt; {
                                            log("Context resumed")
                                            sound.play()
                                            })
                      }
                  catch(e)
                  {
                      log(e)
                  }
              }
  
              function log(m)
              {
                  console.log(m)
                  debug.innerHTML += m+"&lt;br /&gt;"
              }
  
              window.ontouchstart = function()
              {
                  log("ontouchstart()")
                  playSound(myAudio)
                  setTimeout(function() {
                             playSound(myAudio2, 1111)
                             })
              }
          &lt;/script&gt;
      &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p>And ViewController.swift</p>
  
  <pre><code>import UIKit
  import WebKit
  
  class ViewController: UIViewController {
      private var myWebView3 : WKWebView!
      override func viewDidLoad() {
          super.viewDidLoad()
  
          self.myWebView3 = WKWebView(frame: .zero)
  
          self.myWebView3.configuration.preferences.setValue(true, forKey: "allowFileAccessFromFileURLs")
          self.myWebView3.configuration.mediaTypesRequiringUserActionForPlayback = []
          self.myWebView3.configuration.allowsInlineMediaPlayback = true
  
          let url = Bundle.main.url(forResource: "index6", withExtension: "html", subdirectory: "/")!
          self.myWebView3.loadFileURL(url, allowingReadAccessTo: url)
          let request = URLRequest(url: url)
          self.myWebView3.load(request)
  
          self.view.addSubview(self.myWebView3)
      }
  
      override func viewDidLayoutSubviews() {
          self.myWebView3.frame = self.view.bounds
      }
  
  }
  </code></pre>
  
  <p>I'm using Xcode 10.1
  iPhone SE 12.1.1
  I have also tried on an iPad with iOS 10 and get the same error.
  I have also tried context.decodeAudioData() / context.createBufferSource() and get the same error. </p>