如何通过Google Cast SDK将本地视频URI投射到Android TV?转URL方案失效
问题:使用Google Cast SDK投射本地视频URI到Android TV失败
我需要使用Google Cast SDK将本地视频URI投射到Android TV,但现有方案均采用URL。我尝试将URI转换为URL,相关代码如下:
private fun getMediaInfo(name: String, path: String, photoMode: Boolean): MediaInfo { val context = requireActivity().applicationContext val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager val wifiInfo = wifiManager.connectionInfo val ipAddress = Inet4Address.getByAddress( BigInteger.valueOf(wifiInfo.ipAddress.toLong()).toByteArray() ).hostAddress errorLog("ipAddress :: $ipAddress") val url = "http://" + ipAddress + ":" + PORT + "/" + path errorLog("url :: $url") val mediaMetadata = if (photoMode) MediaMetadata(MediaMetadata.MEDIA_TYPE_PHOTO) else MediaMetadata( MediaMetadata.MEDIA_TYPE_MOVIE ) mediaMetadata.putString(MediaMetadata.KEY_TITLE, name) mediaMetadata.addImage(WebImage(Uri.parse(url))) mediaMetadata.addImage(WebImage(Uri.parse(url))) return if (photoMode) MediaInfo.Builder(url) .setContentType("image/jpeg") .setStreamType(MediaInfo.STREAM_TYPE_NONE) .setMetadata(mediaMetadata) .build() else MediaInfo.Builder(url) .setContentType("video/mp4") .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED) .setMetadata(mediaMetadata) .build() }
其中转换URI到URL的代码片段为:
val context = requireActivity().applicationContext val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager val wifiInfo = wifiManager.connectionInfo val ipAddress = Inet4Address.getByAddress( BigInteger.valueOf(wifiInfo.ipAddress.toLong()).toByteArray() ).hostAddress errorLog("ipAddress :: $ipAddress") val url = "http://" + ipAddress + ":" + PORT + "/" + path
但该方案未能生效,不过传入Google上的公开视频URL时可正常投射,请问该如何解决此问题?
解决方案
你的代码只是将本地路径拼接成了HTTP格式的URL,但Android TV(Cast设备)无法直接访问手机本地的文件系统,必须通过一个本地HTTP服务器来暴露文件,Cast设备才能通过网络请求获取到视频文件。以下是具体解决步骤:
1. 启动本地HTTP文件服务器
使用轻量级HTTP服务器库(比如nanohttpd)来搭建本地文件服务,让Cast设备能通过网络访问你的本地文件。
步骤1:添加依赖
在build.gradle(Module级别)中添加nanohttpd依赖:
implementation 'org.nanohttpd:nanohttpd:2.3.1'
步骤2:实现本地文件服务器
创建一个继承自NanoHTTPD的子类,处理文件请求:
class LocalFileServer(port: Int) : NanoHTTPD(port) { override fun serve(session: IHTTPSession): Response { // 移除URL前缀的"/",获取本地文件路径 val filePath = session.uri.removePrefix("/") val targetFile = File(filePath) return if (targetFile.exists() && targetFile.isFile) { // 根据文件后缀设置正确的MIME类型 val mimeType = when { filePath.endsWith(".mp4", ignoreCase = true) -> "video/mp4" filePath.endsWith(".jpg", ignoreCase = true) || filePath.endsWith(".jpeg", ignoreCase = true) -> "image/jpeg" else -> "application/octet-stream" } // 返回文件流 newFixedLengthResponse(Response.Status.OK, mimeType, FileInputStream(targetFile), targetFile.length()) } else { // 文件不存在时返回404 newFixedLengthResponse(Response.Status.NOT_FOUND, "text/plain", "File not found") } } }
步骤3:在Activity中启动/停止服务器
在你的Activity或Fragment中初始化并启动服务器,确保在生命周期结束时停止:
private lateinit var fileServer: LocalFileServer private val SERVER_PORT = 8080 // 选择一个未被占用的端口 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // ... 其他初始化逻辑 try { fileServer = LocalFileServer(SERVER_PORT) fileServer.start() Log.d("FileServer", "Local file server started on port $SERVER_PORT") } catch (e: IOException) { Log.e("FileServer", "Failed to start local server", e) } } override fun onDestroy() { super.onDestroy() if (::fileServer.isInitialized) { fileServer.stop() Log.d("FileServer", "Local file server stopped") } }
2. 修正URL生成逻辑
确保生成的URL能正确映射到本地服务器的文件路径,注意转义特殊字符:
// 在getMediaInfo方法中替换原URL生成代码 val url = "http://$ipAddress:$SERVER_PORT/${Uri.encode(path)}"
3. 权限处理
确保你的App拥有访问本地文件和网络的权限:
- 在
AndroidManifest.xml中添加权限:
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- Android 10+ 如需访问所有外部文件,添加以下权限(需动态申请) --> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
- 动态申请权限(Android 6.0+):确保在访问文件前已经获取到
READ_EXTERNAL_STORAGE或MANAGE_EXTERNAL_STORAGE权限。
4. 验证服务器可用性
在同一局域网的其他设备(比如电脑)的浏览器中访问生成的URL,确认能正常下载或播放文件。如果无法访问,先排查:
- 手机和Android TV是否在同一个WiFi网络
- 服务器端口是否被防火墙拦截
- 文件路径是否正确,App是否有权限访问该文件
完成以上步骤后,再使用Google Cast SDK投射,本地视频就能正常在Android TV上播放了。
内容的提问来源于stack exchange,提问作者Muhammad Sajid
相关产品推荐
相关产品推荐

