如何利用Expo AV实现背景音频播放

问题描述 投票:0回答:1

我在使用 Expo AV 库的 Expo 应用程序中遇到背景音频播放问题。当应用程序位于前台时,音频播放工作正常,但当应用程序进入后台时,音频播放会突然停止。我尝试在音频初始化期间将staysActiveInBackground 选项设置为true,并且还按照建议的步骤在app.json 文件中配置后台音频播放。尽管做出了这些努力,当应用程序失去焦点时,音频播放仍然停止。

我使用 Expo AV 库中的 AudioPlayer 组件来管理音频播放,并且我已确保使用音频源 URI 正确初始化该组件。但是,无论我是在 iOS 还是 Android 设备上测试该应用程序,问题仍然存在。

有人可以提供有关如何确保我的 Expo 应用程序中连续背景音频播放的指导吗?

这是我的组件 Audioplayer 的代码:

import React, { useState, useEffect } from "react";
import { StyleSheet, Text, View, TouchableOpacity } from "react-native";
import { Audio } from "expo-av";
import { Ionicons, MaterialCommunityIcons } from "@expo/vector-icons";
import Slider from "@react-native-community/slider";

export default function App({ uri, stopAudio }) {
  const [audio, setAudio] = useState(null); // audio object
  const [isPlaying, setIsPlaying] = useState(false); // isPlaying state variable to check if audio is playing
  const [position, setPosition] = useState(0); // position state variable to set position of audio
  const [duration, setDuration] = useState(0); // duration state variable to set duration of audio

  useEffect(() => {
    const loadAudio = async () => {
      if (uri) {
        const { sound, status } = await Audio.Sound.createAsync(
          { uri }, // source
          { shouldPlay: true, staysActiveInBackground: true } // initial status: auto play the audio and stay active in background
        );
        setAudio(sound); // set audio object
        setDuration(status.durationMillis); // set duration
        setPosition(0); // reset position
        setIsPlaying(true); // set isPlaying to true
      }
    };

    loadAudio(); // load the audio when the component mounts

    return () => {
      if (audio) {
        setIsPlaying(false); // set isPlaying to false
      }
    };
  }, [uri]);

  useEffect(() => {
    if (audio) {
      // if audio is set then set isPlaying to true
      const updatePosition = setInterval(async () => {
        const currentPosition = await audio.getStatusAsync(); // get current position of audio
        setPosition(currentPosition.positionMillis); // set position state variable
      }, 1000);

      return () => clearInterval(updatePosition); // clear interval to avoid memory leaks
    }
  }, [audio]);

  const setAudioMode = async () => {
    if (audio) {
      await audio.setAudioModeAsync({ staysActiveInBackground: true });
    }
  };

  useEffect(() => {
    setAudioMode();
  }, [audio]);

  // Rest of your component code

  useEffect(() => {
    if (audio) {
      if (stopAudio) {
        audio.stopAsync(); // Stop audio if stopAudio is true
        setIsPlaying(false);
        setPosition(0);
      }
    }
  }, [stopAudio]);

  // Rest of your component code

  const handlePlayPause = async () => {
    if (audio) {
      if (isPlaying) {
        // if audio is playing then pause it
        await audio.pauseAsync();
        setIsPlaying(false);
      } else {
        await audio.playAsync(); // if audio is not playing then play it
        setIsPlaying(true);
      }
    }
  };

  const handleSeek = async (value) => {
    if (audio) {
      await audio.setPositionAsync(value); // seek audio to the position
      setPosition(value);
    }
  };

  const handleStop = () => {
    if (audio) {
      audio.stopAsync();
      setIsPlaying(false);
      setPosition(0);
    }
  };

  return (
    <View style={styles.container}>
      {/* // this button will play/pause the audio */}
      <TouchableOpacity onPress={handlePlayPause} style={{ padding: 10 }}>
        {isPlaying ? (
          <Ionicons name="pause" size={24} color="black" />
        ) : (
          <Ionicons name="play" size={24} color="black" />
        )}
      </TouchableOpacity>

      {/* // this is a progress bar of audio */}
      <Slider
        style={styles.slider} // style
        minimumValue={0}
        maximumValue={duration} // maximum value should be duration of audio
        value={position}
        onSlidingComplete={handleSeek} // seek the audio when slider is moved
        disabled={!audio}
      />
      <Text>
        {Math.floor(position / 1000)}s / {Math.floor(duration / 1000)}s
      </Text>
      <TouchableOpacity onPress={handleStop} style={{ padding: 10 }}>
        <MaterialCommunityIcons name="stop" size={24} color="black" />
      </TouchableOpacity>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center",
    flexDirection: "row",
    flexWrap: "wrap",
  },
  slider: {
    width: "50%",
    marginTop: 20,
  },
});

这里是app.json文件:

{
  "expo": {
    "name": "newtourapp",
    "slug": "newtourapp",
    "version": "1.0.0",
    "orientation": "portrait",
    "icon": "./assets/icon.png",
    "userInterfaceStyle": "light",
    "splash": {
      "image": "./assets/splash.png",
      "resizeMode": "contain",
      "backgroundColor": "#ffffff"
    },
    "assetBundlePatterns": ["**/*"],
    "ios": {
      "supportsTablet": true,
      "infoPlist": {
        "UIBackgroundModes": ["audio"] // This allows audio to play in the background
      }
    },
    "android": {
      "adaptiveIcon": {
        "foregroundImage": "./assets/adaptive-icon.png",
        "backgroundColor": "#ffffff"
      },
      "package": "com.saqibansari.newtourapp"
    },
    "web": {
      "favicon": "./assets/favicon.png"
    },
  }
}

我尝试了几种方法来在我的 Expo 应用程序中实现背景音频播放:

设置staysActiveInBackground:我在音频初始化期间使用Audio.Sound.createAsync 方法使用了staysActiveInBackground 选项,并将其设置为true。我的期望是,当应用程序在后台时,这将允许音频继续播放。

app.json 配置:我在 app.json 文件中添加了必要的配置以支持后台音频播放。具体来说,我在 ios 配置部分包含了 "UIBackgroundModes": ["audio"] 。我希望此配置能够确保应用程序失去焦点时音频播放不会停止。

react-native audio expo playback expo-av
1个回答
0
投票

您需要设置所有音频选项才能正常工作。

Audio.setAudioModeAsync({
    staysActiveInBackground: true,
    playsInSilentModeIOS: true,
    interruptionModeIOS: InterruptionModeIOS.DuckOthers, // Change as you like
    interruptionModeAndroid: InterruptionModeAndroid.DuckOthers, // Change as you like
    shouldDuckAndroid: true,
    playThroughEarpieceAndroid: true,
  });

在 app.json 中,您可能还需要添加 Android 权限:

permissions: ['WAKE_LOCK'],
© www.soinside.com 2019 - 2024. All rights reserved.