一、介绍
本人第一次写博客,如有不妥,还请众多大佬多多包涵和指点,感激不尽
首先,先介绍一下这个项目
目前这个软件内置了53个电视节目,可以直接播放,并且支持手动输入链接播放视频,支持rtmp播放和网络视频。目前这个项目不太完善,但是还是有三个方向可以作为之后扩展的,1直播客户端,2视频播放器,3电视节目播放器。
电视节目取流地址来自:https://blog.csdn.net/qq_32502511/article/details/106855117
在此感谢作者(刘延林 | 梦陆)分享,侵删
app下载地址如下:
https://wws.lanzous.com/igpnaga69sj
密码:bc3b
ipa下载地址如下(只支持越狱iOS安装):
https://wws.lanzous.com/iSE86ga69de
密码:b1eq
项目下载地址如下:
https://wws.lanzous.com/ixdUEga69qh
密码:3vxh
截图如下:
二、代码实现
本人制作的首页极其简陋,如有需要请自行修改。
首页代码如下:
<template>
<view class="content">
<!-- 用for循环将每个节目的按钮及文字输出 -->
<view class="listview" v-for="(item,index) in tv_rtmp">
<button v-on:click="to_tv(index)">
<text>{{index+1}}{{item.name}}</text>
</button>
</view>
<!-- 自助播放,点击后需要输入地址 -->
<view class="other">
<button v-on:click="play_other">自助播放</button>
</view>
<!-- 自定义的含输入框的弹出框 -->
<prompt ref="prompt" @onConfirm="onConfirm" @onCancel="onCancel" title="播放地址" text="请输入播放链接"></prompt>
</view>
</template>
<script>
import prompt from '../../static/prompt.vue'; //导入自定义带输入框的弹出框
export default {
data() {
return {
//电视节目的取流地址及其电视台
//电视节目取流地址来自:https://blog.csdn.net/qq_32502511/article/details/106855117
//在此感谢作者(刘延林 | 梦陆)分享,侵删
tv_rtmp: [
{"name":"CCTV-1综合","path":"rtmp://58.200.131.2:1935/livetv/cctv1"},
{"name":"CCTV-2财经","path":"rtmp://58.200.131.2:1935/livetv/cctv2"},
{"name":"CCTV-3综艺","path":"rtmp://58.200.131.2:1935/livetv/cctv3"},
{"name":"CCTV-4中文国际","path":"rtmp://58.200.131.2:1935/livetv/cctv4"},
{"name":"CCTV-5体育","path":"rtmp://58.200.131.2:1935/livetv/cctv5"},
{"name":"CCTV-6电影","path":"rtmp://58.200.131.2:1935/livetv/cctv6"},
{"name":"CCTV-7军事农业","path":"rtmp://58.200.131.2:1935/livetv/cctv7"},
{"name":"CCTV-8电视剧","path":"rtmp://58.200.131.2:1935/livetv/cctv8"},
{"name":"CCTV-9记录","path":"rtmp://58.200.131.2:1935/livetv/cctv9"},
{"name":"CCTV-10科教","path":"rtmp://58.200.131.2:1935/livetv/cctv10"},
{"name":"CCTV-11戏曲","path":"rtmp://58.200.131.2:1935/livetv/cctv11"},
{"name":"CCTV-12社会与法","path":"rtmp://58.200.131.2:1935/livetv/cctv12"},
{"name":"CCTV-13新闻","path":"rtmp://58.200.131.2:1935/livetv/cctv13"},
{"name":"CCTV-14少儿","path":"rtmp://58.200.131.2:1935/livetv/cctv14"},
{"name":"CCTV-15音乐","path":"rtmp://58.200.131.2:1935/livetv/cctv15"},
{"name":"安徽卫视","path":"rtmp://58.200.131.2:1935/livetv/ahtv"},
{"name":"兵团卫视","path":"rtmp://58.200.131.2:1935/livetv/bttv"},
{"name":"重庆卫视","path":"rtmp://58.200.131.2:1935/livetv/cqtv"},
{"name":"东方卫视","path":"rtmp://58.200.131.2:1935/livetv/dftv"},
{"name":"东南卫视","path":"rtmp://58.200.131.2:1935/livetv/dntv"},
{"name":"广东卫视","path":"rtmp://58.200.131.2:1935/livetv/gdtv"},
{"name":"广西卫视","path":"rtmp://58.200.131.2:1935/livetv/gxtv"},
{"name":"甘肃卫视","path":"rtmp://58.200.131.2:1935/livetv/gstv"},
{"name":"贵州卫视","path":"rtmp://58.200.131.2:1935/livetv/gztv"},
{"name":"湖北卫视","path":"rtmp://58.200.131.2:1935/livetv/hbtv"},
{"name":"湖南卫视","path":"rtmp://58.200.131.2:1935/livetv/hunantv"},
{"name":"河北卫视","path":"rtmp://58.200.131.2:1935/livetv/hebtv"},
{"name":"河南卫视","path":"rtmp://58.200.131.2:1935/livetv/hntv"},
{"name":"黑龙江卫视","path":"rtmp://58.200.131.2:1935/livetv/hljtv"},
{"name":"江苏卫视","path":"rtmp://58.200.131.2:1935/livetv/jstv"},
{"name":"江西卫视","path":"rtmp://58.200.131.2:1935/livetv/jxtv"},
{"name":"吉林卫视","path":"rtmp://58.200.131.2:1935/livetv/jltv"},
{"name":"辽宁卫视","path":"rtmp://58.200.131.2:1935/livetv/lntv"},
{"name":"内蒙古卫视","path":"rtmp://58.200.131.2:1935/livetv/nmtv"},
{"name":"宁夏卫视","path":"rtmp://58.200.131.2:1935/livetv/nxtv"},
{"name":"青海卫视","path":"rtmp://58.200.131.2:1935/livetv/qhtv"},
{"name":"四川卫视","path":"rtmp://58.200.131.2:1935/livetv/sctv"},
{"name":"山东卫视","path":"rtmp://58.200.131.2:1935/livetv/sdtv"},
{"name":"山西卫视","path":"rtmp://58.200.131.2:1935/livetv/sxrtv"},
{"name":"陕西卫视","path":"rtmp://58.200.131.2:1935/livetv/sxtv"},
{"name":"山东教育","path":"rtmp://58.200.131.2:1935/livetv/sdetv"},
{"name":"中国教育1","path":"rtmp://58.200.131.2:1935/livetv/cetv1"},
{"name":"中国教育3","path":"rtmp://58.200.131.2:1935/livetv/cetv3"},
{"name":"中国教育4","path":"rtmp://58.200.131.2:1935/livetv/cetv4"},
{"name":"中国教育2","path":"rtmp://58.200.131.2:1935/livetv/cetv2"},
{"name":"CCTV-第一剧场","path":"rtmp://58.200.131.2:1935/livetv/dyjctv"},
{"name":"CCTV-国防军事","path":"rtmp://58.200.131.2:1935/livetv/gfjstv"},
{"name":"CCTV-怀旧剧场","path":"rtmp://58.200.131.2:1935/livetv/hjjctv"},
{"name":"CCTV-风云剧场","path":"rtmp://58.200.131.2:1935/livetv/fyjctv"},
{"name":"CCTV-风云足球","path":"rtmp://58.200.131.2:1935/livetv/fyzqtv"},
{"name":"CCTV-风云音乐","path":"rtmp://58.200.131.2:1935/livetv/fyyytv"},
{"name":"CCTV-世界地理","path":"rtmp://58.200.131.2:1935/livetv/sjdltv"},
{"name":"CGTN-新闻","path":"rtmp://58.200.131.2:1935/livetv/cctv16"}
]
}
},
onLoad() {
//将地址保存为全局变量,以便视频播放界面使用
getApp().globalData.final_tv_rtmp = this.tv_rtmp
},
components: {//声明自定义组件
prompt,
},
methods: {
to_tv(index){//按钮的点击事件
uni.navigateTo({//在当前页面基础上打开页面
url: '/pages/TV/TV?id=' + index
});
},
play_other(){
this.prompt()
},
//自定义弹出输入框方法
prompt: function() { //显示弹出框
uni.pageScrollTo({ //返回顶部
scrollTop: 0,
duration: 0 //动画时长
})
this.$refs.prompt.show();
},
onConfirm: function(e) { //点击了弹出框的确定按钮
let _cost = e;
if (_cost == '') { //空
console.log('你还未输入');
return;
} else { //输入了
this.$refs.prompt.hide();
uni.navigateTo({
url: '/pages/TV/TV?id=' + _cost
});
}
},
onCancel: function() { //点击了弹出框的取消按钮
this.$refs.prompt.hide();
this.$refs.prompt.cost = '';
},
}
}
</script>
<style>
.listview{
margin-top: 30rpx;
/*给每行按钮增加间距*/
}
.other{
margin-top: 60rpx;
}
</style>
视频播放页如下
<template>
<view>
<!-- 视频播放组件 -->
<video autoplay="true" :src="src" @error="error" @fullscreenchange="fullscreenchange"></video>
<!-- 开启自动播放 播放路径为src变量 播放出差时调用error函数 fullscreenchange视频全屏时调用fullscreenchange函数 -->
<!-- 使用for循环输出节目列表 -->
<view class="list">
<view class="listview" v-for="(item,index) in tv_rtmp">
<button v-on:click="check_tv(index)">
<text>{{index+1}}{{item.name}}</text>
</button>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
src: "", //视频播放地址
tv_rtmp: [],//节目列表
index: "" //当前节目所在视频播放页的位置(下标)
}
},
onLoad(option) {
this.tv_rtmp = getApp().globalData.final_tv_rtmp//获取节目列表
uni.getNetworkType({ //获取网络状态//提示用户断网
success: function(res) {
if (res.networkType == "none") { //没有网络或者网络不好
uni.showToast({
title: "网络走丢了呢",
duration: 1000,
icon: "none"
});
}
}
});
uni.onNetworkStatusChange(function(res) { //网络发生变更时
if (res.isConnected) {//res.isConnected为布尔值,表示当前网络状态
uni.showToast({
title: "网络回来啦",
duration: 1000,
icon: "none"
});
} else
uni.showToast({
title: "网络走丢了呢",
duration: 1000,
icon: "none"
});
});
if (option.id < 1000) {//option.id是用户在首页点击的按钮的下标//小于1000其实是判断option.id是否是数字
this.index = option.id
this.src = this.tv_rtmp[this.index].path
uni.setNavigationBarTitle({ //修改标题为当前节目
title: this.tv_rtmp[this.index].name
})
}else{
this.index = 0
this.src = option.id
uni.setNavigationBarTitle({ //修改标题//防止页面崩溃后标题异常//不一定有效
title: option.id
})
}
},
methods: {
error: function() {
},
fullscreenchange: function(event) {
//智能切换屏幕方向
if (event.detail.fullScreen) { //全屏
plus.screen.lockOrientation("landscape") //自动感应切换屏幕横屏的方向
} else { //全屏切换为小屏
plus.screen.lockOrientation("portrait-primary") //设置屏幕竖直
}
},
check_tv: function(index) {//切换电视频道
this.src = this.tv_rtmp[index].path
this.index = index
uni.setNavigationBarTitle({ //修改标题//防止页面崩溃后标题异常//不一定有效
title: this.tv_rtmp[this.index].name
})
},
}
}
</script>
<style>
video {
width: 750rpx;
position: fixed;
top: 0;
left: 0;
}
.list {
margin-top: 470rpx;
}
.listview {
margin-top: 30rpx;
}
</style>
继续优化用户体验:
uni-app默认软件打开时就获取设备识别码,并且强制获取存储权限,为了用户体验还是很有必要优化一下的。
在项目的manifest.json文件->app-plus->distribute->android中,添加如下代码:
"permissionExternalStorage" : {
//动态获取存储权限//禁止首次打开软件索要
"request" : "none"
},
"permissionPhoneState" : {
//动态获取用户设备信息//禁止首次打开软件索要设备信息
"request" : "none"
}
并且需要根据项目需求适当优化manifest.json文件->app-plus->distribute->android->permissions里的内容,这个标签写的是软件所需的安卓权限,uni-app默认添加了很多原本不需要的权限,在当前这个视频播放项目中可以直接清空。
三、总结
写到这里,这个简陋的项目就已经完成了,我的第一篇博客就此结束,如果发现文中有任何不妥之处,请指正,感谢收看。
来源:oschina
链接:https://my.oschina.net/u/4419312/blog/4545168