尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Cordova+Vue+PHP直播App源码解析:从混合开发到Android打包

Cordova+Vue+PHP直播App源码解析:从混合开发到Android打包 简介一套面向安卓移动开发课程设计和期末大作业的直播APP完整项目包含可运行的Android前端、PHP后端接口与配套说明文档适合计算机相关专业在校学生、老师及初级开发者用作课程设计、毕业设计或项目初期演示。压缩包共49个文件以Vue页面组件、PHP服务端脚本、JavaScript逻辑、JSON配置为主另有21张PNG图片覆盖界面与流程示意整体大小31.79MB目录结构清晰便于按模块查阅。项目代码均经过运行测试功能可用下载后可借助README.md快速了解工程结构与启动方式也便于在此基础上按需修改和扩展新功能满足课程设计或期末作业的个性化要求。目前已有175人浏览学习作为移动开发课设或期末大作业的完整方案读者可从源码层面理解直播类APP的前后端协作、组件化页面组织与接口调用方式兼顾文档说明与可运行代码适合需要快速交付作业或演示项目的场景。1. 拿到直播 App 课设源码先别急着开 Android Studio第一次打开这份Live-Stream-APP-master.zip的人大概率会以为 Android 期末大作业的代码应该是一整个 Gradle 工程。但把压缩包解压之后你会发现根目录下既没有app/模块也没有build.gradle取而代之的是一个src-cordova文件夹和一套完整的 Vue.js 前端代码外加一个app-php后端目录。这个结构说明它走的不是传统原生 Android 开发路线而是 Cordova 混合应用架构Android 外壳由 Cordova 生成业务界面全部用 Vue 组件实现数据层则由 PHP 接口支撑。对于课程设计来说这种选型有它的现实逻辑——单人在一周内同时出界面、交互和后台用 Web 技术栈做 UI 比用 RecyclerView Fragment 快得多而且src-cordova随时可以再从cordova platform add android重新生成就算你把 Android 工程改坏了前端代码依然完好无损。适合计算机相关专业的学生作为课设/期末大作业的起步脚手架也适合想搞明白一套混合 App 从页面到接口怎么串起来的入门开发者。2. 目录结构与工程框架Cordova、Vue 与 PHP 的分工边界2.1 源码包全景先分清哪部分是框架生成哪部分是业务代码把压缩包解压后根目录下的文件可以分为四类。第一类是 Cordova 工程描述文件包括config.xml、src-cordova目录和plugins目录第二类是 Vue 前端项目文件包括src/、public/、babel.config.js、vue.config.js、package.json第三类是 PHP 后端集中在app-php目录下第四类是辅助文件.gitignore和README.md。以下是这四类中关键文件/目录的职责对照路径职责归属src-cordova/Cordova 生成的 Android 原生壳工程构建 APK 时真正被编译的对象Cordovaplugins/Cordova 插件例如摄像头、网络请求等原生能力桥接Cordovaconfig.xml声明 App 的包名、版本、权限、启动页、插件引用Cordovasrc/Vue 的源码目录main.js、App.vue、views/、components/都在这里前端public/构建时原样拷贝的静态资源index.html是 Vue 的挂载入口前端app-php/含login.php、signup.php、func.php、account.php等后端接口后端package.json前端依赖清单记录 Vue、Vue Router、axios 等版本范围前端源码包里的src-cordova不是一份必须手写的代码它是通过cordova platform add android生成的。之所以把这个生成物也放进包里是为了让你在电脑上没有完整 Cordova CLI 环境时也能直接用 Android Studio 打开src-cordova目录进行编译减少课设答辩前的环境配置成本。2.2 config.xml 里的平台配置与权限声明config.xml是所有 Cordova 项目的总控文件类似于原生 Android 里AndroidManifest.xml和build.gradle的混合体。常见的配置项包括 widget 节点的 id即包名、version、description以及platform nameandroid内部的权限声明和启动页配置。widget idcom.example.livestream version1.0.0 xmlnshttp://www.w3.org/ns/widgets nameLiveStreamApp/name description直播课设 Demo/description content srcindex.html / plugin namecordova-plugin-camera spec^4.0.0 / platform nameandroid preference nameAndroidTargetSdkVersion value33 / preference nameAndroidMinSdkVersion value24 / config-file parent/* targetAndroidManifest.xml uses-permission android:nameandroid.permission.INTERNET / uses-permission android:nameandroid.permission.ACCESS_NETWORK_STATE / uses-permission android:nameandroid.permission.WRITE_EXTERNAL_STORAGE android:maxSdkVersion29 / /config-file /platform /widget这里有几个值得注意的参数。minSdkVersion设为 24 意味着目标设备是 Android 7.0 以上避免了很多运行时权限和 FileProvider 的兼容性问题WRITE_EXTERNAL_STORAGE带上maxSdkVersion29是 10.0 之后的推荐写法因为 Android 11 开始强制分区存储过高的 targetSdk 会让这个权限失效。你在 Android Studio 里打开src-cordova工程后最终生成的 Manifest 会把这里的配置合并进去如果出现权限冲突优先检查config.xml而不是直接改 Manifest。2.3 前端构建链vue.config.js 与 public 目录Vue 这边的入口链路是public/index.html→src/main.js→src/App.vue→views/下的页面组件。vue.config.js负责调整 Webpack 的构建行为在 Cordova 场景下最重要的配置是publicPath和devServer的代理规则。module.exports { publicPath: , productionSourceMap: false, devServer: { port: 8080, proxy: { /api: { target: http://10.0.2.2:8080, changeOrigin: true } } } };publicPath必须设置为空字符串否则构建后的 JS/CSS 路径会带上绝对路径/在 Android WebView 里通过file://协议加载index.html时就会找不到资源页面白屏。devServer.proxy只在本地浏览器调试时生效目的是把业务请求转发到本机的 PHP 服务10.0.2.2是 Android 模拟器访问宿主机 localhost 的固定地址真机调试时要改成你电脑在局域网里的 IP否则接口请求会超时。2.4 main.js 挂载了什么Vue 2/3 的初始化逻辑全部集中在src/main.js。它会创建根实例、挂载路由并把那些需要被全局引用的 axios 实例或工具函数挂到原型上。import Vue from vue; import App from ./App.vue; import router from ./router; import request from ./utils/request; Vue.config.productionTip false; Vue.prototype.$http request; new Vue({ router, render: h h(App) }).$mount(#app);Vue.prototype.$http request是典型的 Vue 2 写法目的是让每个页面组件里可以直接通过this.$http.get(/api/...)发起请求不需要在每个组件里重复 import axios。如果你的项目是 Vue 3这个挂载方式会改成app.config.globalProperties.$http request语义一样只是 API 换了。3. 直播侧核心逻辑直播房间与接口对接的实现方式3.1 页面结构从推荐列表到直播房间的跳转链路直播 App 的界面通常拆成两大块一块是直播列表页展示当前正在推流的直播间封面、标题和在线人数另一块是直播房间页负责播放视频流、展示聊天消息。src/views/目录下一般会对应Home.vue、LiveRoom.vue这类组件路由配置写在src/router/下。const routes [ { path: /, name: home, component: () import(../views/Home.vue) }, { path: /room/:id, name: liveRoom, component: () import(../views/LiveRoom.vue), props: true } ];房间页通过路由参数id区分具体是哪一个直播间进入页面后在mounted钩子里根据这个 id 去请求房间详情和播放地址。props: true的作用是把$route.params直接映射到组件的 props 上避免在组件内部到处写this.$route.params.id代码更干净些。如果你喜欢 Option API组件的props字段需要声明id: { type: String, required: true }。3.2 播放器接入如何在 Vue 里调用原生播放能力直播 App 的播放器一般不直接用 HTML5video标签因为 HLS 直播流在现代 WebView 里虽然能播但延迟和弱网表现都不稳定。常见的方案是靠 cordova 插件把原生播放器暴露给 JavaScript在 JS 侧通过window上的全局对象调用。playStream(streamUrl) { const player window.cordova.plugins.StreamPlayer; player.play(streamUrl, (res) { console.log(play started, res); }, (err) { this.errorMsg 播放失败 err.message; }); }cordova.plugins.StreamPlayer是插件暴露出来的命名空间插件在原生侧往往是一个封装了 MediaPlayer 或 ExoPlayer 的类play方法接收一个 RTMP/HTTP-FLV 地址然后在原生层渲染到 SurfaceView 上。这里需要注意直播地址的域名必须配置在config.xml的allow-navigation或allow-intent中否则会被 Cordova 的 URL 白名单拦截。课程设计阶段如果后端没有真实直播流也可以用一段循环播放的测试视频地址替代接口返回的stream_url字段留着即可。3.3 推荐流的加载与列表渲染列表页的数据来源是 PHP 接口比如GET /api/live/list返回一组 JSON 数据前端用 axios 拉取后交给v-for渲染。页面加载时的通用做法是在created阶段发请求同时用一个loading布尔值控制加载中的 UI 状态。data() { return { liveList: [], loading: true, error: }; }, async created() { try { const res await this.$http.get(/api/live/list); this.liveList res.data.data.list; } catch (e) { this.error 接口异常请检查 PHP 服务是否启动; } finally { this.loading false; } }上面的代码做了三件事请求列表接口、把返回的数组交给模板渲染、捕获异常并给出可读的错误提示。需要注意res.data.data.list这个层级关系——外层data是 axios 的响应体格式内层data是 PHP 统一包装的 JSON 结构list才是真正的业务数组。对应到 PHP 后端func.php里一般会封装一个response($code, $msg, $data)函数保证所有接口返回结构一致调试时可以少踩很多坑。4. PHP 后端接口与账号系统登录注册是怎么连通的4.1 后端接口的 URL 规划与请求格式app-php目录里的login.php、signup.php、account.php、func.php构成了后端的全部逻辑。func.php是公共函数库负责数据库连接、CORS 跨域头输出和统一响应格式signup.php处理注册login.php处理登录并下发 tokenaccount.php用于拉取当前用户信息或修改资料。接口设计上课程设计阶段不需要做得太复杂但至少要保持两个约定一是所有接口都返回 JSON二是前端通过Content-Type: application/x-www-form-urlencoded提交参数PHP 端用$_POST读取即可。为了避免跨域问题func.php里会先输出响应头。header(Content-Type: application/json; charsetutf-8); header(Access-Control-Allow-Origin: *); header(Access-Control-Allow-Methods: POST, GET, OPTIONS); header(Access-Control-Allow-Headers: Content-Type);Access-Control-Allow-Origin: *的意思是允许任意来源请求课设阶段图省事没问题但只适合本地调试。如果你的 PHP 部署环境是 Apache/Nginx 同源部署也就是 App 和后端同一个域名这几个头甚至可以不用加浏览器的同源策略在 WebView 里也不会拦截原生发起的请求。4.2 注册与登录的校验流程注册的典型流程是前端拿到用户名和密码发送到signup.php后端先判断用户名是否已被占用若没有则对密码做哈希处理再写入数据库。课程设计常犯的错误是明文存密码这不符合基本的安全习惯而且答辩老师大概率会追问数据库里存的密码能不能被反查。用password_hash可以把密码转成不可逆的哈希串。// signup.php 核心逻辑 $username trim($_POST[username] ?? ); $password $_POST[password] ?? ; if (mb_strlen($username) 3 || mb_strlen($password) 6) { echo response(400, 用户名至少3位密码至少6位, null); exit; } $stmt $pdo-prepare(SELECT id FROM users WHERE username ?); $stmt-execute([$username]); if ($stmt-fetch()) { echo response(400, 用户名已存在, null); exit; } $hash password_hash($password, PASSWORD_DEFAULT); $insert $pdo-prepare(INSERT INTO users (username, password_hash, created_at) VALUES (?, ?, NOW())); $insert-execute([$username, $hash]); echo response(200, 注册成功, null);这段代码的每一步都有明确意义先做参数校验长度不够直接返回再用预处理语句查询用户名避免 SQL 注入最后用password_hash生成密码摘要。登录接口login.php的逻辑是反向的——先按用户名查出哈希串再用password_verify比对用户传来的原密码。$stmt $pdo-prepare(SELECT id, password_hash FROM users WHERE username ?); $stmt-execute([$username]); $user $stmt-fetch(); if ($user password_verify($password, $user[password_hash])) { $token bin2hex(random_bytes(16)); echo response(200, 登录成功, [token $token, user_id $user[id]]); } else { echo response(401, 用户名或密码错误, null); }bin2hex(random_bytes(16))会生成一个 32 位的十六进制随机字符串作为登录令牌课程设计阶段可以直接存在客户端本地后续请求带上它即可识别用户身份。这里不引入 JWT 也没关系重点是讲清楚校验过程——先查哈希再验证密码然后签发凭证。4.3 func.php 里的统一响应封装前面代码里多次出现的response()函数定义在func.php中。它把返回码、消息和数据包在一个标准结构里前端解析时只要盯住这个结构就行。function response($code, $msg, $data null) { return json_encode([ code $code, msg $msg, data $data ], JSON_UNESCAPED_UNICODE); }返回的 JSON 形如{code:200,msg:登录成功,data:{token:...}}。对于开发调试来说JSON_UNESCAPED_UNICODE很有用否则中文会被转成\uXXXX形式的编码在 Android Studio 的 Logcat 和浏览器 Network 面板里看都不直观。如果后端和前端对不上字段优先检查是不是func.php的响应格式被改过。5. Android 端构建打包与四个常见坑5.1 从源码到 APK 的构建路径拿到源码后的标准构建流程分两条路。第一条是用 Cordova CLI在项目根目录依次执行依赖安装和构建命令第二条是直接用 Android Studio 打开src-cordova目录等 Gradle Sync 完成后构建。第二条路更稳因为src-cordova已经是一个完整的 Android 工程。npm install cordova platform add android cordova build android --releasecordova build android核心动作是把src/目录下已构建好的 Web 资源dist/文件夹拷贝到 Android 工程的assets/www目录然后再走 Gradle 打包流程。如果你想先看前端效果可以先用npm run serve在浏览器里跑 Vue 的开发服务器确认页面正常再执行上述命令。这种方式调试速度比每次改完代码重新打包 APK 快得多。5.2 Android Studio 版本与 SDK 版本不匹配打开src-cordova时最常见的报错是 Gradle 版本和 Android Gradle PluginAGP版本不匹配典型的错误信息是Minimum supported Gradle version is X.X.X或者 Android Studio 直接提示Current NDK version is ...。Cordova 生成工程里的 Gradle 版本是被锁定在platforms/android/cordova/lib/里的一般不用手动改。解决思路是先在src-cordova里找到build.gradle确认 AGP 版本再让它和本地 Android Studio 兼容。SDK 相关的报错则检查platforms/android下的project.properties或config.xml里的targetSdkVersion是否已被本机安装的 SDK 版本覆盖。Android Studio 里提示某 SDK 组件无法勾选时通常是 sdkmanager 的 license 没接受执行sdkmanager --licenses全部接受即可。5.3 真机调试时的 fileprovider 与存储权限问题直播 App 如果需要把视频帧截图或录制片段保存到本地就会涉及文件读写权限。Android 7.0 以上使用content://URI 时必须依赖 FileProvider而 Cordova 插件内部如果不兼容分区存储就会在后台日志里看到类似content://com.tencent.wework.fileprovider/external_path/android/data/...的 URI 报错。这个路径里的包名是插件或宿主工程定义的 authority报错时先确认res/xml/file_paths.xml里是否声明了对应的外部路径以及调用FileProvider.getUriForFile时传入的 authority 和清单里是否一致。真机上另一个典型问题是 Android 9.0 默认禁止明文 HTTP 流量。如果你的 PHP 接口是http://192.168.x.x:8080这种地址WebView 里的请求会被系统拦截。处理办法是在config.xml里加上android:usesCleartextTraffictrue或者用networkSecurityConfig配置允许指定域名的明文流量。具体配置写在 Cordova 的config-file区块里Android Studio 重新编译后生效。5.4 断点不命中时检查哪里调src-cordova里的 Java 代码时Android Studio 可能提示「当前不会命中断点」通常有两个原因一个是 Debug 构建类型没有开启 debuggable 属性在build.gradle的buildTypes { debug { debuggable true } }里加一行就好另一个是运行的进程和断点所在的代码不是同一份特别是 Cordova 工程里可能存在多套assets/www改的是 Vue 源码但断点打在旧的构建产物里。实际上WebView 里的 JS 断点调试更推荐用 Chrome DevTools 远程调试在 Chrome 地址栏输入chrome://inspect找到设备上的 WebView 实例直接在 Sources 面板里断点调试src/下的前端代码不需要经过 Android 构建链路。本文还有配套的精品资源点击获取
返回列表