com.google.api.client.googleapis.json.GoogleJson响应异常:401未经授权



我有以下代码:

package com.example.bluelightlite.modules
import android.content.Context
import android.os.AsyncTask
import com.example.bluelightlite.builders.ServiceBuilder
import com.google.api.client.auth.oauth2.Credential
import com.google.api.client.http.javanet.NetHttpTransport
import com.google.api.client.util.DateTime
import com.google.api.services.calendar.Calendar
import com.google.api.services.calendar.model.Event
import com.google.api.services.calendar.model.Events
class GoogleCalendarsServiceModule constructor(context: Context): AsyncTask<Void, Void, List<Event>>() {
private val googleCredential: Credential
private val httpTransport: NetHttpTransport = NetHttpTransport()
private val googleCredentialsUtilityModule = GoogleCredentialsUtilityModule(context)
init {
this.googleCredential = this.googleCredentialsUtilityModule.execute(this.httpTransport).get()
}
private var googleCalendarService: Calendar =
ServiceBuilder().buildGoogleCalendarService(this.googleCredential, this.httpTransport)
/**
* gets all calendar events
* @return Events list
*/
private fun getEvents(): List<Event> {
val now = DateTime(System.currentTimeMillis())
val events: Events = this.googleCalendarService
.events()
.list("Marc Freeman")
.setMaxResults(10)
.setOrderBy("startTime")
.execute()
return events.items;
}
override fun doInBackground(vararg params: Void?): List<Event> {
return this.getEvents()
}
}

应用程序要求用户接受访问日历的权限,我有一个身份验证令牌,但当我调用时:

GoogleCalendarsServiceModule.execute() // because it needs to run on another thread

我得到这个错误:

E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
Process: com.example.bluelightlite, PID: 11410
java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask$4.done(AsyncTask.java:399)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
at java.util.concurrent.FutureTask.run(FutureTask.java:271)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:289)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
Caused by: com.google.api.client.googleapis.json.GoogleJsonResponseException: 401 Unauthorized
{
"code" : 401,
"errors" : [ {
"domain" : "global",
"location" : "Authorization",
"locationType" : "header",
"message" : "Invalid Credentials",
"reason" : "authError"
} ],
"message" : "Invalid Credentials"
}
at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:113)
at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:40)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest$1.interceptResponse(AbstractGoogleClientRequest.java:321)
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1065)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:419)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:352)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:469)
at com.example.bluelightlite.modules.GoogleCalendarsServiceModule.getEvents(GoogleCalendarsServiceModule.kt:38)
at com.example.bluelightlite.modules.GoogleCalendarsServiceModule.doInBackground(GoogleCalendarsServiceModule.kt:44)
at com.example.bluelightlite.modules.GoogleCalendarsServiceModule.doInBackground(GoogleCalendarsServiceModule.kt:14)
at android.os.AsyncTask$3.call(AsyncTask.java:378)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
... 4 more

如何将我的访问令牌传递到我的请求中?当我调用GoogleCalendarService时,我似乎找不到一个允许我这样做的API,顺便说一句,这绝对让Android失望。

所以我不知道发生了什么,但我清理了我的项目,代码工作了。。。如下所示:

class GoogleCalendarsServiceModule constructor(context: Context) {
private val googleCredential: Credential
private val httpTransport: NetHttpTransport = NetHttpTransport()
private val googleCredentialsUtilityModule = GoogleCredentialsUtilityModule(context)
private var googleCalendarService: Calendar
init {
this.googleCredential = this.googleCredentialsUtilityModule.execute(this.httpTransport).get()
this.googleCalendarService = ServiceBuilder().buildGoogleCalendarService(this.googleCredential, this.httpTransport)
}
/**
* gets all calendar events
* @see - https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-i-o.html
* @return Events list
*/
suspend fun getCalendarEvents(): List<Event> = withContext(Dispatchers.IO) {
val now = DateTime(System.currentTimeMillis())
val events: Calendar.Events? = googleCalendarService.events()
val allEvents = events!!.list("primary")
.setMaxResults(10)
.setTimeMin(now)
.setOrderBy("startTime")
.setSingleEvents(true)
.execute()
allEvents.items
}
suspend fun getCalendarEventsForRoom(roomName: String): List<Event> = withContext(Dispatchers.IO) {
val now = DateTime(System.currentTimeMillis())
val events: Calendar.Events? = googleCalendarService.events()
val allEventsForRoom = events!!.list("primary")
.setMaxResults(10)
.setTimeMin(now)
.setOrderBy("startTime")
.setSingleEvents(true)
.execute()
allEventsForRoom.items.distinctBy { x -> x.location == roomName }
}
}

凭据模块,用于设置和维护Google 0Auth凭据。包括设置令牌文件夹(如果丢失(。

class GoogleCredentialsUtilityModule constructor(private val context: Context): AsyncTask<NetHttpTransport, Void, Credential>() {
/**
* Starts getting credentials on a different thread by implementing
* AsyncTask<>()
* @param params: a list of parameters
* @return none
*/
override fun doInBackground(vararg params: NetHttpTransport): Credential {
return this.getCredentials(params[0])
}
/**
* Creates an authorized Credential object.
* @param HTTP_TRANSPORT The network HTTP Transport.
* @return An authorized Credential object.
* @throws java.io.IOException If the credentials.json file cannot be found.
*/
private fun getCredentials(HTTP_TRANSPORT: NetHttpTransport): Credential {
val inputStream: InputStream = getCredentialsAsInputStream()
val clientSecrets: GoogleClientSecrets = GoogleClientSecrets.load(JSON_FACTORY, InputStreamReader(inputStream))
createTokenFolderIfMissing()
val authorisationFlow: GoogleAuthorizationCodeFlow = getAuthorisationFlow(HTTP_TRANSPORT, clientSecrets)
val localServerReceiver: LocalServerReceiver = LocalServerReceiver.Builder().setPort(43783).build()
val ab: AuthorizationCodeInstalledApp =
object : AuthorizationCodeInstalledApp(authorisationFlow, localServerReceiver) {
@Throws(IOException::class)
override fun onAuthorization(authorizationUrl: AuthorizationCodeRequestUrl) {
val url = authorizationUrl.build()
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
context.startActivity(browserIntent)
}
}
return ab.authorize("user")
}
/**
* Gets the /credentials.json file
* @return InputStream
*/
private fun getCredentialsAsInputStream(): InputStream {
return this.javaClass.getResourceAsStream(CREDENTIALS_FILE_PATH)
?: throw FileNotFoundException("Resource Not found: $CREDENTIALS_FILE_PATH")
}
/**
* Creates the Tokens Folder for Google Authentication
* Uses the current context for the folder path from
* Context.getExternalFilesDir()
*/
private fun createTokenFolderIfMissing() {
val tokenFolder = getTokenFolder()
if (!tokenFolder.exists()) {
tokenFolder.mkdir()
}
}
/**
* gets External storage directory from the
* current context
* @return File
*/
private fun getTokenFolder(): File {
return File(this.context.getExternalFilesDir("")?.absolutePath + TOKENS_DIRECTORY_PATH)
}
/**
* Gets authorisation flow so that the application can authenticate into Google Calendars
* @param HTTP_TRANSPORT allows the app to use HTTP connections
* @param clientSecrets secrets for authentication into Google
* @return GoogleAuthorizationCodeFlow
*/
private fun getAuthorisationFlow(HTTP_TRANSPORT: NetHttpTransport, clientSecrets: GoogleClientSecrets): GoogleAuthorizationCodeFlow {
return GoogleAuthorizationCodeFlow.Builder(
HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
.setDataStoreFactory(FileDataStoreFactory(getTokenFolder()))
.setAccessType("offline")
.build()
}
}

最后,使用协同例程调用服务:

class MainActivity : AppCompatActivity(), CoroutineScope, IMeetingRoomDelegate {
private var job: Job = Job()
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job
@Inject
lateinit var permissionsUtilityModule: PermissionsUtilityModule
private lateinit var googleCalendarsServiceModule: GoogleCalendarsServiceModule
private lateinit var meetingRooms: MeetingRooms
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
DaggerUtilityModuleComponent.create().inject(this)
this.permissionsUtilityModule.checkUserPermissions(this)
this.googleCalendarsServiceModule = GoogleCalendarsServiceModule(this);
launch {
val events: List<Event> = googleCalendarsServiceModule.getCalendarEvents()
meetingRooms = setMeetingRooms(events)
setMeetingRoomFragments(meetingRooms)
}
setContentView(R.layout.activity_main)
}
override fun onDestroy() {
super.onDestroy()
this.job.cancel()
}
override fun onMeetingRoomFragmentClicked(fragment: MeetingRoomFragment, meetingRoom: MeetingRoom) {
val intent = Intent(this, ViewMeetingRoomDataActivity::class.java)
intent.putExtra("meetingRoomData", meetingRoom)
startActivity(intent)
}
private fun setMeetingRooms(events: List<Event>): MeetingRooms {
val mappedEvents: List<MeetingEvent> = mapMeetingEvents(events)
val meetingEvents = MeetingEvents(mappedEvents)
return MeetingRoomFactory().getRooms(meetingEvents)
}
private fun setMeetingRoomFragments(mappedMeetingRooms: MeetingRooms) {
for(meetingRoom: MeetingRoom in mappedMeetingRooms.getMeetingRooms()) {
val bundle = Bundle()
val meetingRoomFragment = MeetingRoomFragment()
bundle.putParcelable("meetingRoomData", meetingRoom)
meetingRoomFragment.arguments = bundle
supportFragmentManager.beginTransaction()
.add(R.id.root_container, meetingRoomFragment)
.commitAllowingStateLoss()
}
}
}

我想我会发帖,以防有人需要帮助处理整个0Auth繁琐的程序。

最新更新