You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 08:14:52