我正在开发使用Google Calendar API的Android应用程序。我遵循Google Developers网站上显示的标准示例。但是我每次都收到403 Forbidden的错误。
我的代码。
public class CalendarActivityMain extends Activity
implements EasyPermissions.PermissionCallbacks {
GoogleAccountCredential mCredential;
private TextView mOutputText;
private Button mCallApiButton;
ProgressDialog mProgress;
static final int REQUEST_ACCOUNT_PICKER = 1000;
static final int REQUEST_AUTHORIZATION = 1001;
static final int REQUEST_GOOGLE_PLAY_SERVICES = 1002;
static final int REQUEST_PERMISSION_GET_ACCOUNTS = 1003;
private static final String BUTTON_TEXT = "Call Google Calendar API";
private static final String PREF_ACCOUNT_NAME = "accountName";
private static final String[] SCOPES = { CalendarScopes.CALENDAR_READONLY };
/**
* Create the main activity.
* @param savedInstanceState previously saved instance data.
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout activityLayout = new LinearLayout(this);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT);
activityLayout.setLayoutParams(lp);
activityLayout.setOrientation(LinearLayout.VERTICAL);
activityLayout.setPadding(16, 16, 16, 16);
ViewGroup.LayoutParams tlp = new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
mCallApiButton = new Button(this);
mCallApiButton.setText(BUTTON_TEXT);
mCallApiButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mCallApiButton.setEnabled(false);
mOutputText.setText("");
getResultsFromApi();
mCallApiButton.setEnabled(true);
}
});
activityLayout.addView(mCallApiButton);
mOutputText = new TextView(this);
mOutputText.setLayoutParams(tlp);
mOutputText.setPadding(16, 16, 16, 16);
mOutputText.setVerticalScrollBarEnabled(true);
mOutputText.setMovementMethod(new ScrollingMovementMethod());
mOutputText.setText(
"Click the \'" + BUTTON_TEXT +"\' button to test the API.");
activityLayout.addView(mOutputText);
mProgress = new ProgressDialog(this);
mProgress.setMessage("Calling Google Calendar API ...");
setContentView(activityLayout);
// Initialize credentials and service object.
mCredential = GoogleAccountCredential.usingOAuth2(
getApplicationContext(), Arrays.asList(SCOPES))
.setBackOff(new ExponentialBackOff());
}
/**
* Attempt to call the API, after verifying that all the preconditions are
* satisfied. The preconditions are: Google Play Services installed, an
* account was selected and the device currently has online access. If any
* of the preconditions are not satisfied, the app will prompt the user as
* appropriate.
*/
private void getResultsFromApi() {
if (! isGooglePlayServicesAvailable()) {
acquireGooglePlayServices();
} else if (mCredential.getSelectedAccountName() == null) {
chooseAccount();
} else if (! isDeviceOnline()) {
mOutputText.setText("No network connection available.");
} else {
new MakeRequestTask(mCredential).execute();
}
}
/**
* Attempts to set the account used with the API credentials. If an account
* name was previously saved it will use that one; otherwise an account
* picker dialog will be shown to the user. Note that the setting the
* account to use with the credentials object requires the app to have the
* GET_ACCOUNTS permission, which is requested here if it is not already
* present. The AfterPermissionGranted annotation indicates that this
* function will be rerun automatically whenever the GET_ACCOUNTS permission
* is granted.
*/
@AfterPermissionGranted(REQUEST_PERMISSION_GET_ACCOUNTS)
private void chooseAccount() {
if (EasyPermissions.hasPermissions(
this, Manifest.permission.GET_ACCOUNTS)) {
String accountName = getPreferences(Context.MODE_PRIVATE)
.getString(PREF_ACCOUNT_NAME, null);
if (accountName != null) {
mCredential.setSelectedAccountName(accountName);
getResultsFromApi();
} else {
// Start a dialog from which the user can choose an account
startActivityForResult(
mCredential.newChooseAccountIntent(),
REQUEST_ACCOUNT_PICKER);
}
} else {
// Request the GET_ACCOUNTS permission via a user dialog
EasyPermissions.requestPermissions(
this,
"This app needs to access your Google account (via Contacts).",
REQUEST_PERMISSION_GET_ACCOUNTS,
Manifest.permission.GET_ACCOUNTS);
}
}
/**
* Called when an activity launched here (specifically, AccountPicker
* and authorization) exits, giving you the requestCode you started it with,
* the resultCode it returned, and any additional data from it.
* @param requestCode code indicating which activity result is incoming.
* @param resultCode code indicating the result of the incoming
* activity result.
* @param data Intent (containing result data) returned by incoming
* activity result.
*/
@Override
protected void onActivityResult(
int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch(requestCode) {
case REQUEST_GOOGLE_PLAY_SERVICES:
if (resultCode != RESULT_OK) {
mOutputText.setText(
"This app requires Google Play Services. Please install " +
"Google Play Services on your device and relaunch this app.");
} else {
getResultsFromApi();
}
break;
case REQUEST_ACCOUNT_PICKER:
if (resultCode == RESULT_OK && data != null &&
data.getExtras() != null) {
String accountName =
data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
if (accountName != null) {
SharedPreferences settings =
getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = settings.edit();
editor.putString(PREF_ACCOUNT_NAME, accountName);
editor.apply();
mCredential.setSelectedAccountName(accountName);
getResultsFromApi();
}
}
break;
case REQUEST_AUTHORIZATION:
if (resultCode == RESULT_OK) {
getResultsFromApi();
}
break;
}
}
/**
* Respond to requests for permissions at runtime for API 23 and above.
* @param requestCode The request code passed in
* requestPermissions(android.app.Activity, String, int, String[])
* @param permissions The requested permissions. Never null.
* @param grantResults The grant results for the corresponding permissions
* which is either PERMISSION_GRANTED or PERMISSION_DENIED. Never null.
*/
@Override
public void onRequestPermissionsResult(int requestCode,
@NonNull String[] permissions,
@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
EasyPermissions.onRequestPermissionsResult(
requestCode, permissions, grantResults, this);
}
/**
* Callback for when a permission is granted using the EasyPermissions
* library.
* @param requestCode The request code associated with the requested
* permission
* @param list The requested permission list. Never null.
*/
@Override
public void onPermissionsGranted(int requestCode, List<String> list) {
// Do nothing.
}
/**
* Callback for when a permission is denied using the EasyPermissions
* library.
* @param requestCode The request code associated with the requested
* permission
* @param list The requested permission list. Never null.
*/
@Override
public void onPermissionsDenied(int requestCode, List<String> list) {
// Do nothing.
}
/**
* Checks whether the device currently has a network connection.
* @return true if the device has a network connection, false otherwise.
*/
private boolean isDeviceOnline() {
ConnectivityManager connMgr =
(ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
return (networkInfo != null && networkInfo.isConnected());
}
/**
* Check that Google Play services APK is installed and up to date.
* @return true if Google Play Services is available and up to
* date on this device; false otherwise.
*/
private boolean isGooglePlayServicesAvailable() {
GoogleApiAvailability apiAvailability =
GoogleApiAvailability.getInstance();
final int connectionStatusCode =
apiAvailability.isGooglePlayServicesAvailable(this);
return connectionStatusCode == ConnectionResult.SUCCESS;
}
/**
* Attempt to resolve a missing, out-of-date, invalid or disabled Google
* Play Services installation via a user dialog, if possible.
*/
private void acquireGooglePlayServices() {
GoogleApiAvailability apiAvailability =
GoogleApiAvailability.getInstance();
final int connectionStatusCode =
apiAvailability.isGooglePlayServicesAvailable(this);
if (apiAvailability.isUserResolvableError(connectionStatusCode)) {
showGooglePlayServicesAvailabilityErrorDialog(connectionStatusCode);
}
}
/**
* Display an error dialog showing that Google Play Services is missing
* or out of date.
* @param connectionStatusCode code describing the presence (or lack of)
* Google Play Services on this device.
*/
void showGooglePlayServicesAvailabilityErrorDialog(
final int connectionStatusCode) {
GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance();
Dialog dialog = apiAvailability.getErrorDialog(
CalendarActivityMain.this,
connectionStatusCode,
REQUEST_GOOGLE_PLAY_SERVICES);
dialog.show();
}
/**
* An asynchronous task that handles the Google Calendar API call.
* Placing the API calls in their own task ensures the UI stays responsive.
*/
private class MakeRequestTask extends AsyncTask<Void, Void, Void> {
private com.google.api.services.calendar.Calendar mService = null;
private Exception mLastError = null;
/*public MakeRequestTask(GoogleAccountCredential credential) {
HttpTransport transport = AndroidHttp.newCompatibleTransport();
JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
mService = new com.google.api.services.calendar.Calendar.Builder(
transport, jsonFactory, credential)
.setApplicationName("Google Calendar API Android Quickstart")
.build();
}*/
public MakeRequestTask(GoogleAccountCredential mCredential) {
HttpTransport transport = AndroidHttp.newCompatibleTransport();
JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
mService = new com.google.api.services.calendar.Calendar.Builder(
transport, jsonFactory, mCredential)
.setApplicationName("Call Google Calendar API")
.build();
}
/**
* Background task to call Google Calendar API.
* @param params no parameters needed for this task.
*/
@Override
protected Void doInBackground(Void... params) {
try {
getDataFromApi();
return null;
} catch (Exception e) {
mLastError = e;
cancel(true);
return null;
}
}
/**
* Fetch a list of the next 10 events from the primary calendar.
* @return List of Strings describing returned events.
* @throws IOException
*/
private void getDataFromApi() throws IOException {
/*// List the next 10 events from the primary calendar.
DateTime now = new DateTime(System.currentTimeMillis());
List<String> eventStrings = new ArrayList<String>();
Events events = mService.events().list("primary")
.setMaxResults(10)
.setTimeMin(now)
.setOrderBy("startTime")
.setSingleEvents(true)
.execute();
List<Event> items = events.getItems();
for (Event event : items) {
DateTime start = event.getStart().getDateTime();
if (start == null) {
// All-day events don't have start times, so just use
// the start date.
start = event.getStart().getDate();
}
eventStrings.add(
String.format("%s (%s)", event.getSummary(), start));
}
return eventStrings;*/
Event event = new Event()
.setSummary("Google I/O 2015")
.setLocation("800 Howard St., San Francisco, CA 94103")
.setDescription("A chance to hear more about Google's developer products.");
DateTime startDateTime = new DateTime("2017-05-28T09:00:00-07:00");
EventDateTime start = new EventDateTime()
.setDateTime(startDateTime)
.setTimeZone("America/Los_Angeles");
event.setStart(start);
DateTime endDateTime = new DateTime("2017-05-28T17:00:00-07:00");
EventDateTime end = new EventDateTime()
.setDateTime(endDateTime)
.setTimeZone("America/Los_Angeles");
event.setEnd(end);
String[] recurrence = new String[] {"RRULE:FREQ=DAILY;COUNT=2"};
event.setRecurrence(Arrays.asList(recurrence));
EventAttendee[] attendees = new EventAttendee[] {
new EventAttendee().setEmail("[email protected]"),
new EventAttendee().setEmail("[email protected]"),
};
event.setAttendees(Arrays.asList(attendees));
EventReminder[] reminderOverrides = new EventReminder[] {
new EventReminder().setMethod("email").setMinutes(24 * 60),
new EventReminder().setMethod("popup").setMinutes(10),
};
Event.Reminders reminders = new Event.Reminders()
.setUseDefault(false)
.setOverrides(Arrays.asList(reminderOverrides));
event.setReminders(reminders);
String calendarId = "primary";
event = mService.events().insert(calendarId, event).execute();
System.out.printf("Event created: %s\n", event.getHtmlLink());
}
@Override
protected void onPreExecute() {
mOutputText.setText("");
mProgress.show();
}
@Override
protected void onPostExecute(Void aVoid) {
mProgress.hide();
}
/*@Override
protected Void onPostExecute() {
mProgress.hide();
*//*if (output == null || output.length() == 0) {
mOutputText.setText("No results returned.");
} else {
//output.add(0, "Data retrieved using the Google Calendar API:");
mOutputText.setText(TextUtils.join("\n", output));
}*//*
return null;
}*/
@Override
protected void onCancelled() {
mProgress.hide();
if (mLastError != null) {
if (mLastError instanceof GooglePlayServicesAvailabilityIOException) {
showGooglePlayServicesAvailabilityErrorDialog(
((GooglePlayServicesAvailabilityIOException) mLastError)
.getConnectionStatusCode());
} else if (mLastError instanceof UserRecoverableAuthIOException) {
startActivityForResult(
((UserRecoverableAuthIOException) mLastError).getIntent(),
CalendarActivityMain.REQUEST_AUTHORIZATION);
} else {
mOutputText.setText("The following error occurred:\n"
+ mLastError.getMessage());
}
} else {
mOutputText.setText("Request cancelled.");
}
}
}
}
错误:
com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden
08-22 11:46:49.507 2210-2345/com.ridhs.vaccinesample W/System.err: {
08-22 11:46:49.507 2210-2345/com.ridhs.vaccinesample W/System.err: "code" : 403,
08-22 11:46:49.508 2210-2345/com.ridhs.vaccinesample W/System.err: "errors" : [ {
08-22 11:46:49.508 2210-2345/com.ridhs.vaccinesample W/System.err: "domain" : "global",
08-22 11:46:49.508 2210-2345/com.ridhs.vaccinesample W/System.err: "message" : "Insufficient Permission",
08-22 11:46:49.508 2210-2345/com.ridhs.vaccinesample W/System.err: "reason" : "insufficientPermissions"
08-22 11:46:49.508 2210-2345/com.ridhs.vaccinesample W/System.err: } ],
08-22 11:46:49.508 2210-2345/com.ridhs.vaccinesample W/System.err: "message" : "Insufficient Permission"
08-22 11:46:49.508 2210-2345/com.ridhs.vaccinesample W/System.err: }
08-22 11:46:49.508 2210-2345/com.ridhs.vaccinesample W/System.err: at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:113)
08-22 11:46:49.508 2210-2345/com.ridhs.vaccinesample W/System.err: at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:40)
08-22 11:46:49.508 2210-2345/com.ridhs.vaccinesample W/System.err: at com.google.api.client.googleapis.services.AbstractGoogleClientRequest$1.interceptResponse(AbstractGoogleClientRequest.java:321)
08-22 11:46:49.508 2210-2345/com.ridhs.vaccinesample W/System.err: at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1065)
08-22 11:46:49.508 2210-2345/com.ridhs.vaccinesample W/System.err: at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:419)
08-22 11:46:49.508 2210-2345/com.ridhs.vaccinesample W/System.err: at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:352)
08-22 11:46:49.508 2210-2345/com.ridhs.vaccinesample W/System.err: at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:469)
08-22 11:46:49.508 2210-2345/com.ridhs.vaccinesample W/System.err: at com.ridhs.vaccinesample.CalendarActivityMain$MakeRequestTask.getDataFromApi(CalendarActivityMain.java:426)
08-22 11:46:49.509 2210-2345/com.ridhs.vaccinesample W/System.err: at com.ridhs.vaccinesample.CalendarActivityMain$MakeRequestTask.doInBackground(CalendarActivityMain.java:352)
08-22 11:46:49.509 2210-2345/com.ridhs.vaccinesample W/System.err: at com.ridhs.vaccinesample.CalendarActivityMain$MakeRequestTask.doInBackground(CalendarActivityMain.java:319)
08-22 11:46:49.509 2210-2345/com.ridhs.vaccinesample W/System.err: at android.os.AsyncTask$2.call(AsyncTask.java:292)
08-22 11:46:49.509 2210-2345/com.ridhs.vaccinesample W/System.err: at java.util.concurrent.FutureTask.run(FutureTask.java:237)
08-22 11:46:49.509 2210-2345/com.ridhs.vaccinesample W/System.err: at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
08-22 11:46:49.509 2210-2345/com.ridhs.vaccinesample W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
08-22 11:46:49.509 2210-2345/com.ridhs.vaccinesample W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
08-22 11:46:49.509 2210-2345/com.ridhs.vaccinesample W/System.err: at java.lang.Thread.run(Thread.java:818)
请帮我。
最佳答案
如我所见,您正在尝试创建一个事件,但是您正在发送具有只读作用域的请求。
使用范围CalendarScopes.CALENDAR
代替CalendarScopes.CALENDAR_READONLY
应该可以解决问题。
或者,您可以只使用CalendarScopes.all()
方法。
从其文档中:
返回一个不可修改的集合,其中包含由此声明的所有范围
类。