react-native-video无法播放远程mp3文件替代方法

近日在学习react-native的时候想做一个类似音乐播放器的工具,各方百度使用react-native-video 作为音视频播放组件。但是该组件在播放远程mp3文件的时候一直播放不出来,播放mp4文件正常。几经周折选择了使用react-native-sound 组件替代播放,具体代码如下

import React, {Component} from 'react';
import {
    AppRegistry,
    StyleSheet,
    Dimensions,
    Text,
    Image,
    View,
    Slider,
    TouchableOpacity,
    ScrollView,
    ActivityIndicator,
    Animated,
    Easing,
    Alert
} from 'react-native';

// import { Slider } from 'react-native-elements'
import Sound from 'react-native-sound'
import config from "../../config";

let lyrObj = []   // 存放歌词
let {width, height} = Dimensions.get('window');
let mp3 = "";
//如果是网络音频,使用 new Sound(mp3,null,error => {})
let whoosh = null;

export default class MusicTest extends Component {
    constructor(props) {
        super(props);
        this.spinValue = new Animated.Value(0)
        this.state = {
            volume: 0.5,
            seconds: 0, //秒数
            totalMin: '', //总分钟
            totalSec: '', //总分钟秒数
            nowMin: 0, //当前分钟
            nowSec: 0, //当前秒钟
            maximumValue: 0, //滑块最大值,
            songs: [],   //歌曲id数据源
            playModel: 1,  // 播放模式  1:列表循环    2:随机    3:单曲循环
            btnModel: "http://qiniu.guang.lerzen.com/liebiaoxunhuan.png", //播放模式按钮背景图
            pic_small: '',    //小图
            pic_big: '',      //大图
            song_id: '',     //歌曲id
            title: '',       //歌曲名字
            author: '',      //歌曲作者
            file_link: '',   //歌曲播放链接
            songLyr: [],     //当前歌词
            sliderValue: 0,    //Slide的value
            pause: false,       //歌曲播放/暂停
            currentTime: 0.0,   //当前时间
            duration: 0.0,     //歌曲时间
            currentIndex: 0,    //当前第几首
            isplayBtn: "http://qiniu.guang.lerzen.com/zhanting.png"  //播放/暂停按钮背景图
        }
    }

    // 旋转动画
    spin = () => {
        this.spinValue.setValue(0)
        myAnimate = Animated.timing(
            this.spinValue,
            {
                toValue: 1,
                duration: 4000,
                easing: Easing.linear
            }
        ).start(() => this.spin())
    }
    loadSongInfo = (index) => {
        //加载歌曲
        let songid = this.state.songs[index]
        let url = config.serverUrl + "/Music/GetMusicInfo/getMusicInfo?songId=" + songid
        fetch(url)
            .then((response) => response.json())
            .then((responseJson) => {
                let songinfo = responseJson.data.songinfo
                let bitrate = responseJson.data.bitrate
                this.setState({
                    pic_small: songinfo.pic_small, //小图
                    pic_big: songinfo.pic_big,  //大图
                    title: songinfo.title,     //歌曲名
                    author: songinfo.author,   //歌手
                    file_link: bitrate.file_link,   //播放链接
                })
                whoosh = new Sound(bitrate.file_link, null, (error) => {
                    if (error) {
                        return console.log('资源加载失败', error);
                    }
                })
                let totalTime = bitrate.file_duration;//歌曲长度
                let totalMin = parseInt(totalTime / 60); //总分钟数
                let totalSec = totalTime - totalMin * 60; //秒钟数并判断前缀是否 + '0'
                totalSec = totalSec > 9 ? totalSec : '0' + totalSec;
                this.setState({
                    totalMin,
                    totalSec,
                    maximumValue: totalTime,
                })
                this.onGetLyric(songid);
            })
    }
    onGetMusicLists = () => {
        let url = config.serverUrl + "/Music/GetMusicLists/getMusicLists";
        fetch(url)
            .then((response) => response.json())
            .then((responseJson) => {
                let listAry = responseJson.data.song_list
                let song_idAry = []; //保存song_id的数组
                for (let i = 0; i < listAry.length; i++) {
                    let song_id = listAry[i].song_id
                    song_idAry.push(song_id)
                }
                this.setState({
                    songs: song_idAry
                }, () => {
                    this.loadSongInfo(0)
                })
            })
            .catch((error) => { // 错误处理
                // Alert.alert(JSON.stringify(error))
            })
    }
    onGetLyric = (songId) => {
        //加载歌词
        let url = config.serverUrl + "/Music/GetMusicLyric/getMusicLyric?songId=" + songId;
        fetch(url)
            .then((response) => response.json())
            .then((responseJson) => {
                    let lry = responseJson.data.lrcContent
                    let lryAry = lry.split('\n')   //按照换行符切数组
                    lryAry.forEach(
                        function (val, index) {
                            let obj = {}   //用于存放时间
                            val = val.replace(/(^\s*)|(\s*$)/g, '')    //正则,去除前后空格
                            let indeofLastTime = val.indexOf(']')  // ]的下标
                            let timeStr = val.substring(1, indeofLastTime) //把时间切出来 0:04.19
                            let minSec = ''
                            let timeMsIndex = timeStr.indexOf('.')  // .的下标
                            if (timeMsIndex !== -1) {
                                //存在毫秒 0:04.19
                                minSec = timeStr.substring(1, val.indexOf('.'))  // 0:04.
                                obj.ms = parseInt(timeStr.substring(timeMsIndex + 1, indeofLastTime))  //毫秒值 19
                            } else {
                                //不存在毫秒 0:04
                                minSec = timeStr
                                obj.ms = 0
                            }
                            let curTime = minSec.split(':')  // [0,04]
                            obj.min = parseInt(curTime[0])   //分钟 0
                            obj.sec = parseInt(curTime[1])   //秒钟 04
                            obj.txt = val.substring(indeofLastTime + 1, val.length) //歌词文本: 留下唇印的嘴
                            obj.txt = obj.txt.replace(/(^\s*)|(\s*$)/g, '')
                            obj.dis = false
                            obj.total = obj.min * 60 + obj.sec + obj.ms / 100   //总时间
                            if (obj.txt.length > 0) {
                                lyrObj.push(obj)
                            }
                        }
                    )
                }
            )
    }

    componentDidMount() {
        //先从总列表中获取到song_id保存
        this.onGetMusicLists();
        this.spin()   //   启动旋转
    }

    // 上一曲
    prevAction = (index) => {
        this.recover()
        lyrObj = [];
        if (index == -1) {
            index = this.state.songs.length - 1 // 如果是第一首就回到最后一首歌
        }
        this.setState({
            currentIndex: index  //更新数据
        })
        this.loadSongInfo(index)  //加载数据
    }
    // 下一曲
    nextAction = (index) => {
        this.recover()
        lyrObj = [];
        if (index == 10) {
            index = 0 //如果是最后一首就回到第一首
        }
        this.setState({
            currentIndex: index,  //更新数据
        })
        this.loadSongInfo(index)   //加载数据
    }
    // 播放/暂停
    playAction = () => {
        let pauseStatus = !this.state.pause;
        this.setState({
            pause: !this.state.pause
        })
        //判断按钮显示什么(播放)
        if (pauseStatus == true) {
            this.setState({
                isplayBtn: "http://qiniu.guang.lerzen.com/bofang.png"
            })
            this.start();
        } else {
            // 暂停
            this.setState({
                isplayBtn: "http://qiniu.guang.lerzen.com/zhanting.png"
            })
            this.pause();
        }
    }

    componentWillUnmount() {
        this.time && clearTimeout(this.time);
    }

// 歌词
    renderItem() {
        // 数组
        let itemAry = [];
        for (let i = 0; i < lyrObj.length; i++) {
            let item = lyrObj[i].txt

            if (this.state.currentTime.toFixed(2) > lyrObj[i].total) {
                //正在唱的歌词
                itemAry.push(
                    <View key={i} style={styles.itemStyle}>
                        <Text style={{color: 'blue'}}> {item} </Text>
                    </View>
                );
                _scrollView.scrollTo({x: 0, y: (25 * i), animated: false});
            }
            else {
                //所有歌词
                itemAry.push(
                    <View key={i} style={styles.itemStyle}>
                        <Text style={{color: 'red'}}> {item} </Text>
                    </View>
                )
            }
        }

        return itemAry;
    }

//把秒数转换为时间类型
    formatTime = (time) => {
        // 71s -> 01:11
        let min = Math.floor(time / 60)
        let second = time - min * 60
        min = min >= 10 ? min : '0' + min
        second = second >= 10 ? second : '0' + second
        return min + ':' + second
    }
    // 开始播放
    start = () => {
        whoosh.play();
        this.time = setInterval(() => {
            whoosh.getCurrentTime(seconds => {
                seconds = Math.ceil(seconds);
                this.onGetNowTime(seconds)
            })
        }, 1000)
    }
    // 暂停
    pause = () => {
        clearInterval(this.time);
        whoosh.pause();
    }
    // 停止
    stop = () => {
        clearInterval(this.time);
        this.setState({
            nowMin: 0,
            nowSec: 0,
            seconds: 0,
        })
        whoosh.stop();
    }

    recover = () => {
        if (whoosh) {
            this.pause();
            this.stop();
            whoosh = null;
        }
        this.setState({
            pause: false,
            isplayBtn: "http://qiniu.guang.lerzen.com/zhanting.png",  //播放/暂停按钮背景图
            seconds: 0,
            currentTime: 0.0
        })
    }
    // 时间处理
    onGetNowTime = (seconds) => {
        let nowMin = this.state.nowMin,
            nowSec = this.state.nowSec;
        if (seconds >= 60) {
            nowMin = parseInt(seconds / 60); //当前分钟数
            nowSec = seconds - nowMin * 60;
            nowSec = nowSec < 10 ? '0' + nowSec : nowSec;
        } else {
            nowSec = seconds < 10 ? '0' + seconds : seconds;
        }
        this.setState({
            nowMin,
            nowSec,
            seconds
        })
        this.setState({
            currentTime: seconds
        })
    }

    render() {
        if (this.state.file_link.length <= 0) {
            return (
                <ActivityIndicator
                    animating={this.state.animating}
                    style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}
                    size="large"/>
            )
        } else {
            const spin = this.spinValue.interpolate({
                inputRange: [0, 1],
                outputRange: ['0deg', '360deg']
            })
            return (
                <View style={styles.container}>
                    {/*背景大图*/}
                    <Image source={{uri: this.state.pic_big}} style={{flex: 1}}/>
                    {/*背景白色透明遮罩*/}
                    <View style={{
                        position: 'absolute',
                        width: width,
                        height: height,
                        backgroundColor: 'white',
                        opacity: 0.8
                    }}/>
                    <View style={{position: 'absolute', width: width}}>
                        {/*胶片光盘*/}
                        <Image source={{uri: "http://qiniu.guang.lerzen.com/jianpianpan.png"}} style={{width: 220, height: 220, alignSelf: 'center'}}/>

                        {/*旋转小图*/}
                        <Animated.Image
                            ref='myAnimate'
                            style={{
                                width: 140,
                                height: 140,
                                marginTop: -180,
                                alignSelf: 'center',
                                borderRadius: 140 * 0.5,
                                transform: [{rotate: spin}]
                            }}
                            source={{uri: this.state.pic_small}}
                        />
                        {/*歌曲信息*/}
                        <View style={styles.playingInfo}>
                            {/*作者-歌名*/}
                            <Text>{this.state.author} - {this.state.title}</Text>
                            {/*时间*/}
                            <Text>{this.state.nowMin}:{this.state.nowSec} - {this.state.totalMin}:{this.state.totalSec}</Text>
                        </View>
                        {/*播放模式*/}
                        <View style={{marginTop: 5, marginBottom: 5, marginLeft: 20}}>
                            <TouchableOpacity onPress={() => this.playModel(this.state.playModel)}>
                                <Image source={{uri: this.state.btnModel}} style={{width: 20, height: 20}}/>
                            </TouchableOpacity>
                        </View>
                        {/*进度条*/}
                        <Slider
                            ref='slider'
                            // disabled //禁止滑动
                            maximumTrackTintColor={'#ccc'} //右侧轨道的颜色
                            minimumTrackTintColor={'skyblue'} //左侧轨道的颜色
                            maximumValue={this.state.maximumValue} //滑块最大值
                            minimumValue={0} //滑块最小值
                            step={1}
                            value={this.state.seconds}
                            onSlidingComplete={(value) => { //用户完成更改值时调用的回调(例如,当滑块被释放时)
                                value = parseInt(value);
                                this.onGetNowTime(value)
                                // 设置播放时间
                                whoosh.setCurrentTime(value);
                            }}
                            onValueChange={(value) => {
                                this.onGetNowTime(value)
                            }}
                        />
                        {/*歌词*/}
                        <View style={{height: 280, alignItems: 'center', marginTop: 20}}>
                            <ScrollView style={{position: 'relative'}}
                                        showsVerticalScrollIndicator={false}
                                        ref={(scrollView) => {
                                            _scrollView = scrollView
                                        }}
                            >
                                {this.renderItem()}
                            </ScrollView>
                        </View>
                        {/*歌曲按钮*/}
                        <View style={{flexDirection: 'row', justifyContent: 'space-around',marginTop:20}}>
                            <TouchableOpacity onPress={() => this.prevAction(this.state.currentIndex - 1)}>
                                <Image source={{uri: "http://qiniu.guang.lerzen.com/shangyishou.png"}}
                                       style={{width: 30, height: 30}}/>
                            </TouchableOpacity>

                            <TouchableOpacity onPress={() => this.playAction()}>
                                <Image source={{uri: this.state.isplayBtn}} style={{width: 30, height: 30}}/>
                            </TouchableOpacity>

                            <TouchableOpacity onPress={() => this.nextAction(this.state.currentIndex + 1)}>
                                <Image source={{uri: "http://qiniu.guang.lerzen.com/xiayishou.png"}}
                                       style={{width: 30, height: 30}}/>
                            </TouchableOpacity>
                        </View>
                        {/*<Text>{time.nowMin}:{time.nowSec}/{time.totalMin}:{time.totalSec}</Text>*/}
                        {/*<Text>当前音量: {this.state.volume}</Text>*/}
                        {/*<Text onPress={this._addVolume}>声音+</Text>*/}
                        {/*<Text onPress={this._reduceVolume}>声音-</Text>*/}
                        {/*<Text onPress={this._stop}>停止</Text>*/}
                    </View>
                </View>
            );
        }
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
    },
    image: {
        flex: 1
    },
    playingControl: {
        flexDirection: 'row',
        alignItems: 'center',
        paddingTop: 10,
        paddingLeft: 20,
        paddingRight: 20,
        paddingBottom: 20
    },
    playingInfo: {
        flexDirection: 'row',
        alignItems: 'stretch',
        justifyContent: 'space-between',
        paddingTop: 40,
        paddingLeft: 20,
        paddingRight: 20,
        backgroundColor: 'rgba(255,255,255,0.0)'
    },
    text: {
        color: "black",
        fontSize: 22
    },
    modal: {
        height: 300,
        borderTopLeftRadius: 5,
        borderTopRightRadius: 5,
        paddingTop: 5,
        paddingBottom: 50
    },
    itemStyle: {
        paddingTop: 20,
        height: 25,
        backgroundColor: 'rgba(255,255,255,0.0)'
    }
});

可以实现歌词同步,前后音乐切换。部分样式是参照网上大神的哦。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_42547619/article/details/87798108
今日推荐