使用服务账号JSON创建GoogleCredential时遇FileNotFoundException问题
问题分析与解决
问题重现
获取AccessToken的代码如下:
@Throws(IOException::class) private fun getAccessToken(): String? { val googleCredentials = GoogleCredentials .fromStream(FileInputStream("campusshop-8bbd7-firebase-adminsdk-4j10y-4b35043fe3.json")) .createScoped(Arrays.asList(SCOPES)) googleCredentials.refreshAccessToken() return googleCredentials.accessToken.tokenValue }
无论传入何种路径,都会抛出错误:
Caused by: java.io.FileNotFoundException: service-account.json: open failed: ENOENT (No such file or directory)
且JSON文件与包含getAccessToken方法的文件处于同一目录。
核心原因
FileInputStream依赖的是程序运行时的工作目录,而非代码文件所在的目录。即便JSON和代码文件同目录,程序启动时的工作路径可能是项目根目录、编译输出目录等,导致找不到目标文件。
可行解决方案
方案1:通过类加载器读取资源文件
如果JSON文件是项目的资源文件(需确保被打包到编译产物中),用类加载器获取输入流是更可靠的方式:
@Throws(IOException::class) private fun getAccessToken(): String? { val inputStream = javaClass.classLoader?.getResourceAsStream("campusshop-8bbd7-firebase-adminsdk-4j10y-4b35043fe3.json") ?: throw IOException("无法找到服务账号JSON文件") val googleCredentials = GoogleCredentials .fromStream(inputStream) .createScoped(Arrays.asList(SCOPES)) googleCredentials.refreshAccessToken() return googleCredentials.accessToken.tokenValue }
注意:需将JSON文件放在项目的资源目录下(比如Java/Kotlin项目的src/main/resources,Android项目的src/main/res/raw),确保编译时会被打包到classpath中。
方案2:使用文件绝对路径
若能确定文件的绝对路径,可直接指定(不推荐,移植性差):
// Windows用双反斜杠,Linux/macOS用正斜杠 val filePath = "/Users/xxx/project/app/src/main/resources/campusshop-8bbd7-firebase-adminsdk-4j10y-4b35043fe3.json" val inputStream = FileInputStream(filePath)
方案3:配置项目资源路径
如果要保留JSON和代码文件同目录的结构,可在Gradle项目中配置资源目录,让编译器将代码目录下的JSON文件打包为资源:
// build.gradle.kts sourceSets { main { resources { srcDirs("src/main/kotlin/com/yourpackage") // 替换为你的代码目录 } } }
配置完成后,用方案1的类加载器方式读取即可。
内容的提问来源于stack exchange,提问作者Danil
相关产品推荐
相关产品推荐

