安卓Kotlin项目中向Google Sheet写入数据的问题求助
Android端Kotlin接入Google Sheets API 解决未解析引用与通信问题
问题背景
我正在开发一款Android App,需要将手机端获取的GPS数据更新至Google电子表格。已完成云项目创建、开启Sheets API、获取API密钥,并添加了以下依赖:
implementation 'com.google.api-client:google-api-client:2.2.0' implementation 'com.google.oauth-client:google-oauth-client-jetty:1.34.1' implementation 'com.google.apis:google-api-services-sheets:v4-rev20230227-2.0.0' implementation 'com.google.http-client:google-http-client-gson:1.42.3'
但现有教程多为Java/Python版本,转Kotlin后出现FATAL EXCEPTION,同时存在两个核心未解析引用错误:
GoogleAccountCredential未解析引用sheetsService未解析引用
另外对credentials.json的放置位置和授权方式也存在疑问。
问题代码示例
import android.annotation.SuppressLint import android.content.Context import android.content.Intent import android.content.pm.PackageManager import android.location.Location import android.location.LocationListener import android.location.LocationManager import android.os.Bundle import android.widget.* import androidx.appcompat.app.AppCompatActivity import androidx.core.app.ActivityCompat import com.google.api.client.googleapis.auth.oauth2.* import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport import com.google.api.client.http.HttpTransport import com.google.api.services.sheets.v4.* import java.io.* import java.util.* //private val CREDENTIALS_FILE_PATH = "/credentials.json" //I see Java code using .json file to auth the permission,I put file in "app\src\main\res", but I'm not sure is crroect or not. class MainActivity : AppCompatActivity() { private val SCOPES = listOf(SheetsScopes.SPREADSHEETS) private val googleSheetID = "MYSHEETID" private val googleSheetName = "MYSHEETNAME_TOO" private val range = "B1" //I have changed that to my sheet ID. val credential = GoogleAccountCredential.usingOAuth2(this, listOf(SheetsScopes.SPREADSHEETS)) //I create OAuth2 and service account too. //GoogleAccountCredential UNRESOLVE REFERENCE error @SuppressLint("RestrictedApi") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager val locationListener = object : LocationListener { override fun onLocationChanged(location: Location) { findViewById<TextView>(R.id.longitude).text = location.longitude.toString() findViewById<TextView>(R.id.latitude).text = location.latitude.toString() } override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {} override fun onProviderEnabled(provider: String) {} override fun onProviderDisabled(provider: String) {} } findViewById<Button>(R.id.load_from_GPS).setOnClickListener { if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { Toast.makeText(this,"@string/btn_GPS",Toast.LENGTH_SHORT).show() ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION), 1) return@setOnClickListener } locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0L, 0f, locationListener) } findViewById<Button>(R.id.reportBt).setOnClickListener { val textView0: TextView = findViewById(R.id.longitude) val textView1: TextView = findViewById(R.id.latitude) val textTemp0 = textView0.text.toString() val textTemp1 = textView1.text.toString() textTemp = textTemp0+","+textTemp1 val valueRange = ValueRange().setValues(listOf(listOf(textTemp))) sheetsService.spreadsheets().values() .update(googleSheetID, googleSheetName + "!" + range, valueRange) .setValueInputOption("RAW") .execute() }//sheetsService UNRESOLVE REFERENCE error } }
解决方案
1. 修复依赖缺失
GoogleAccountCredential属于Android端OAuth库,当前依赖中的google-oauth-client-jetty是桌面端组件,需替换为Android版依赖:
// 移除桌面端依赖 // implementation 'com.google.oauth-client:google-oauth-client-jetty:1.34.1' // 添加Android端OAuth依赖 implementation 'com.google.oauth-client:google-oauth-client-android:1.34.1' // 添加Google账号登录支持 implementation 'com.google.android.gms:play-services-auth:20.7.0' // 添加协程依赖(用于异步网络请求) implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.2'
2. 正确处理Credentials与授权
- credentials.json需放置在
app/src/main/assets目录(无assets文件夹则手动创建),而非res目录。 - 正确初始化
GoogleAccountCredential并引导用户选择Google账号:
private lateinit var credential: GoogleAccountCredential private val REQUEST_ACCOUNT_PICKER = 1000 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 初始化Credential credential = GoogleAccountCredential.usingOAuth2( this, SCOPES ).setBackOff(ExponentialBackOff()) // 启动账号选择界面 startActivityForResult(credential.newChooseAccountIntent(), REQUEST_ACCOUNT_PICKER) } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) when(requestCode) { REQUEST_ACCOUNT_PICKER -> { if (resultCode == RESULT_OK && data != null) { val accountName = data.getStringExtra(android.accounts.AccountManager.KEY_ACCOUNT_NAME) accountName?.let { credential.selectedAccountName = it // 账号选择完成后初始化Sheets服务 initSheetsService() } } } } }
3. 初始化sheetsService
sheetsService未解析是因为未定义和初始化,需在授权完成后创建实例:
private lateinit var sheetsService: Sheets private fun initSheetsService() { val httpTransport = com.google.api.client.extensions.android.http.AndroidHttp.newCompatibleTransport() val jsonFactory = com.google.api.client.json.gson.GsonFactory.getDefaultInstance() sheetsService = Sheets.Builder(httpTransport, jsonFactory, credential) .setApplicationName("你的App名称") .build() }
4. 修复代码中的其他问题
- 补充
textTemp变量定义:
val textTemp = textTemp0 + "," + textTemp1
- 网络请求不能在主线程执行,改用协程异步处理:
findViewById<Button>(R.id.reportBt).setOnClickListener { val textView0: TextView = findViewById(R.id.longitude) val textView1: TextView = findViewById(R.id.latitude) val textTemp0 = textView0.text.toString() val textTemp1 = textView1.text.toString() val textTemp = textTemp0 + "," + textTemp1 val valueRange = ValueRange().setValues(listOf(listOf(textTemp))) lifecycleScope.launch(Dispatchers.IO) { try { sheetsService.spreadsheets().values() .update(googleSheetID, "$googleSheetName!$range", valueRange) .setValueInputOption("RAW") .execute() launch(Dispatchers.Main) { Toast.makeText(this@MainActivity, "数据提交成功", Toast.LENGTH_SHORT).show() } } catch (e: Exception) { e.printStackTrace() launch(Dispatchers.Main) { Toast.makeText(this@MainActivity, "提交失败:${e.message}", Toast.LENGTH_SHORT).show() } } } }
5. 添加网络权限
在AndroidManifest.xml中添加:
<uses-permission android:name="android.permission.INTERNET" />
内容的提问来源于stack exchange,提问作者FrankieK
相关产品推荐
相关产品推荐

