background

In daily requirement development, A user clicks A specific song on page A to jump to page B, and the ID of the song is required to be carried. The song can be automatically played on page B.

Use the audio tag on the page:

// React <audio ref={this.audioRef} SRC ={playingMusicSource} autoPlay loop Play the song enclosing audioRef. Current. Play ();Copy the code

Self-test stage, with their iPhone test found that everything is normal, feel very perfect πŸ˜„

Delivered to PM, PM found that the song did not automatically play 😭 after entering page B

Problem orientation

I asked the PM to use an Android phone (working at home due to the epidemic), but he did not have an Android phone at hand, so I used Chrome to try to reproduce the problem first. Open the console and find the following error πŸ‘‡ :

Click on the link given in the error prompt, and it is found that this is a strict autoplay policy of Google. Simply put, Google does not allow autoplay in the case of users without any interaction or some Settings in advance for the sake of user experience.

Of course, there are some scenarios where autoplay is allowed :(again, the user has to do something)

To solve

In Chrome:

I was desperate when I found this strategy, but on second thought, since Google made this rule from the perspective of user experience, is it unreasonable for PM?

  • Solution 1: Communicate with PM and add an interaction to page B?

I briefly introduced Google’s relevant strategies and the user experience considerations behind them to PM. PM expressed his understanding, BUT the actual situation is that page A has not been allowed to play due to legal issues, and it is expected to be played on page B. There needs to be another interaction, which is too long for the song playing path.

Practical result: I didn’t convince PM, PM convinced me. πŸ˜…

As a result, both of us are trying to figure out how to be more appropriate.

  • Solution two: netease and other music players can be automatically broadcast, how to do?

I have checked many methods (there are many online), some of them seem to be reliable (such as timed rotation training), but they are not feasible (maybe the operation posture is not correct).

Due to the time crunch, the night… For an easy method, use

After testing, iframe can play automatically without limitation.

The actual transformation

The next step is modification. Since

Simple: create an iframe on the body and add it dynamically.

if(X) {/ / X for some conditions need to automatically play the judgment of the const musicInfo = musicList. Find (item = > item. Id_str = = = currentMusicId) | | {}; const newUri = get(musicInfo,'play_url.url_list[0]');
      this.iframeNode = document.createElement('iframe');
      this.iframeNode.setAttribute('src', newUri);
      this.iframeNode.setAttribute('allow'.'autoplay');
      this.iframeNode.setAttribute('hidden'.true); Const time = Number(musicinfo.duration) * 1000 + 3000; // Musicinfo.duration * 1000 + 3000; // Because iframe cannot listen for the end of playback or loop playback, // Therefore set timer, after the end of the song playback icon switch to stop 🀚 icon this.iframeNodeTimer =setTimeout(() => { this.pauseMusicPlay(); this.clearIframeNodeTimer(); // Clear timer this.cleariframenode (); }, time); // Add the created Element to the body. document.body.appendChild(this.iframeNode); this.setState({ musicPaused:false,
        playingMusicSource: newUri,
      });
    }
Copy the code

In the real world, there are a few more questions:

  • After the user enters the page, the user will pause the song that is being played before the song is finished
  • After the user enters the page, the user clicks to play other songs before the song is finished
  • After the user enters the page, the song has been played, and the user can play any song

Since the first entry uses iframe playback, additional processing is required when the user clicks pause ⏸️ and switches between songs that are playing.

After the user clicks on the song cover, it responds to the handlePlayMusic event, in which additional processing needs to be done for the iframe element created.

// Clear timer clearIframeNodeTimer = () => {if(this.iframeNodeTimer) { this.iframeNodeTimer && clearTimeout(this.iframeNodeTimer); this.iframeNodeTimer = null; } // clearIframeNode clearIframeNode = () => {if(this.iframeNode) { document.body.removeChild(this.iframeNode); this.iframeNode = null; }} handlePlayMusic = idStr => {// if this.iframeNode exists // this.iframeNode exists: // At this time, the user should respond to the action of "pause" to stop playing the current song. // If the user clicks another song, other songs will be playedif (this.iframeNode) {
      document.body.removeChild(this.iframeNode);
      this.iframeNode = null;
      this.pauseMusicPlay();
      if(newUri ! == playingMusicSource) { const currentIndex = musicList.findIndex(item => item.id_str === idStr); this.togglePlayer({ action:'play', uri: newUri, musicId: idStr, order: currentIndex, tabName: this.tabName });
      }
      return; } // Other normal playback logic}Copy the code

For the three possible scenarios above: the presence or absence of this.iframeNode is used as an indication of whether the first song is finished playing. If this. IframeNode exists, this. IframeNode needs special processing. If it does not exist, this.

Within the Android client

Rely on the ability, the setMediaPlaybackRequiresUserGesture within the end (the default is true), set to false.

Harvest summary

  • The demand needs to be careful, the plan needs to research
  • Strong container capacity
  • There are other pits?? . Grow slowly in the pit