一、介绍

首先,先介绍一下这个项目
目前这个软件内置了53个电视节目,可以直接播放,并且支持手动输入链接播放视频,支持rtmp播放和网络视频。目前这个项目不太完善,但是还是有三个方向可以作为之后扩展的,1直播客户端,2视频播放器,3电视节目播放器。

电视节目取流地址来自:https://blog.csdn.net/qq_32502511/article/details/106855117
在此感谢作者(刘延林 | 梦陆)分享,侵删

app下载地址如下:
https://wws.lanzous.com/iuVtAgc4ygh
密码:bvtk

项目下载地址如下:
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默认添加了很多原本不需要的权限,在当前这个视频播放项目中可以直接清空。

三、总结

写到这里,这个简陋的项目就已经完成了,我的第一篇博客就此结束,如果发现文中有任何不妥之处,请指正,感谢收看。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐