ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

如何使我的Android应用使用“服务帐户”访问共享的Google日历?

2019-10-27 17:25:24  阅读:220  来源: 互联网

标签:google-calendar-api android


我认为答案是肯定的,但我不确定该怎么做.我一直在使用API​​从存储在设备上的日历中获取事件.例如

 public static ArrayList<MINCalendarEvent> queryEvents(long startMillis, long endMillis) throws  MINPermissionException
 {
    if ( ContextCompat.checkSelfPermission(MINMainActivity.getSharedInstance(), Manifest.permission.WRITE_CALENDAR) != PackageManager.PERMISSION_GRANTED )
    {
        throw new MINPermissionException(NO_PERMISSION);
    }
    else
    {
        ArrayList<MINCalendarEvent> eventArray = new ArrayList<MINCalendarEvent>();

        Cursor cur = CalendarContract.Instances.query(MINMainActivity.getSharedInstance().getContentResolver(), EVENT_PROJECTION, startMillis, endMillis);
        int numItems = cur.getCount();
        Log.d("MINCalendarUtils.queryEvents", "Number of events retrieved: " + numItems);
        while (cur.moveToNext())
        {
            MINCalendarEvent event = new MINCalendarEvent();
            event.calendarID = cur.getLong(EVENT_PROJECTION_CALENDAR_ID);
            event.organizer = cur.getString(EVENT_PROJECTION_ORGANIZER);
            event.title = cur.getString(EVENT_PROJECTION_TITLE);
            event.eventLocation = cur.getString(EVENT_PROJECTION_EVENT_LOCATION);
            event.description = cur.getString(EVENT_PROJECTION_DESCRIPTION);
            event.dtStart = cur.getLong(EVENT_PROJECTION_DTSTART);
            event.dtEnd = cur.getLong(EVENT_PROJECTION_DTEND);
            event.eventTimeZone = cur.getString(EVENT_PROJECTION_EVENT_TIMEZONE);
            event.eventEndTimeZone = cur.getString(EVENT_PROJECTION_EVENT_END_TIMEZONE);
            event.duration = cur.getString(EVENT_PROJECTION_DURATION);
            event.allDay = (cur.getInt(EVENT_PROJECTION_ALL_DAY) != 0);
            event.rRule = cur.getString(EVENT_PROJECTION_RRULE);
            event.rDate = cur.getString(EVENT_PROJECTION_RDATE);
            event.availability = cur.getInt(EVENT_PROJECTION_AVAILABILITY);
            event.guestsCanModify = (cur.getInt(EVENT_PROJECTION_GUESTS_CAN_MODIFY) != 0);
            event.guestsCanInviteOthers = (cur.getInt(EVENT_PROJECTION_GUESTS_CAN_INVITE_OTHERS) != 0);
            event.guestsCanSeeGuests = (cur.getInt(EVENT_PROJECTION_GUESTS_CAN_SEE_GUESTS) != 0);
            eventArray.add(event);
        }
        return eventArray;
    }
}

这很好.问题是我需要查询用户也没有权限的服务器上存储的共享日历.我的应用程序创建了一个本地日历.我需要访问用户也将没有权限的共享,并将存储在共享日历中的事件与本地日历同步(不同步).我假设我可以使用服务帐户来访问共享日历.

我已经成功创建了一个服务帐户并将该帐户添加到共享日历中.怎么办????

似乎有几种使用服务帐户访问日历事件的方法,但我完全感到困惑.显然,我想使用我一直在使用的API,但我认为它仅适用于与设备同步的日历.

我已经使用“ GoogleCredentials”进行了调查,但是我需要一些示例源代码来完成这项工作.首先,当我创建服务帐户时,我使用JSON而不是p12导出了该帐户.我看不到如何使用它.该API似乎需要p12.拥有凭证后,我也对如何使用凭证感到完全困惑.这是我开始的示例源:

    //String emailAddress = "123456789000-abc123def456@developer.gserviceaccount.com";
    GoogleCredential credential = null;
    JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
    HttpTransport httpTransport = null;
    try
    {
        httpTransport = GoogleNetHttpTransport.newTrustedTransport();
        credential = new GoogleCredential.Builder()
                .setTransport(httpTransport)
                .setJsonFactory(JSON_FACTORY)
                .setServiceAccountId(emailAddress)
                .setServiceAccountPrivateKeyFromP12File(new File("MyProject.p12"))
                .setServiceAccountScopes(Collections.singleton(SQLAdminScopes.SQLSERVICE_ADMIN))
                .build();
    }
    catch (GeneralSecurityException e)
    {
        e.printStackTrace();
    }
    catch (IOException e)
    {
        e.printStackTrace();
    }

有几个问题. 1)我无法将其编译.我似乎无法使导入工作:

 import com.google.api.services.sqladmin.SQLAdminScopes;

假设我可以克服这个问题,那么现在.我不确定如何使用凭据访问远程日历.我需要从共享日历中获取事件列表.

我也一直在通过以下链接查看源代码中的说明,但未使用服务帐户:https://developers.google.com/google-apps/calendar/quickstart/android

此外,是否有办法将更改挂接到基于服务器的共享日历上,以便在共享日历发生更改时可以ping通?

有帮助吗???

编辑-工作代码

根据Andres的回答,我整理了以下代码:

public static void calendarAuthenticate()
{
    Thread thread = new Thread(new Runnable()
    {
        @Override
        public void run()
        {
            try
            {
                MINAppConfiguration appConfig = MINAppConfiguration.getSharedInstance();

                // Application Name
                appName = appConfig.getCurrentAppInfo().appName;

                // Directory to store user credentials for this application;
                //dataStoreDir = new File(appConfig.appDirectoryOnDevice);

                // Instance of the JSON factory
                jsonFactory = JacksonFactory.getDefaultInstance();

                // Instance of the scopes required
                scopes = new ArrayList<String>();
                scopes.add(CalendarScopes.CALENDAR_READONLY);

                // Http transport creation
                httpTransport = AndroidHttp.newCompatibleTransport();

                java.io.File licenseFile = getSecretFile();
                GoogleCredential credential = new GoogleCredential.Builder()
                        .setTransport(httpTransport)
                        .setJsonFactory(jsonFactory)
                        .setServiceAccountId("account-1@handy-contact-762.iam.gserviceaccount.com")
                        .setServiceAccountScopes(scopes)
                        .setServiceAccountPrivateKeyFromP12File(licenseFile)
                        .build();
                com.google.api.services.calendar.Calendar.Builder builder = new com.google.api.services.calendar.Calendar.Builder(httpTransport, jsonFactory, credential);
                builder.setApplicationName(appName);
                com.google.api.services.calendar.Calendar client = builder.build();

                // List the next 10 events from the target calendar.
                DateTime now = new DateTime(System.currentTimeMillis());
                com.google.api.services.calendar.Calendar.Events.List list = client.events().list("mobilityinitiative.com_qfvbdrk368f9la06hacb4bduos@group.calendar.google.com");
                list.setMaxAttendees(10);
                list.setTimeMin(now);
                list.setOrderBy("startTime");
                list.setSingleEvents(true);
                Events events = list.execute();

                List<Event> items = events.getItems();
                if (items.size() == 0)
                {
                    Log.d(TAG, "No upcoming events found.");
                }
                else
                {
                    Log.d(TAG, "Upcoming events");
                    for (Event event : items) {
                        DateTime start = event.getStart().getDateTime();
                        if (start == null) {
                            start = event.getStart().getDate();
                        }
                        Log.d(TAG, event.getSummary() + " (" + start + ")\n");
                    }
                }
            }
            catch (GeneralSecurityException e)
            {
                e.printStackTrace();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    });
    thread.start();
}

public static java.io.File getSecretFile()
{
    File f = new File(MINMainActivity.getSharedInstance().getCacheDir()+ "/" +"google_calendar_secret.p12");
    if (f.exists())
    {
        f.delete();
    }
    try
    {
        InputStream is = MINMainActivity.getSharedInstance().getAssets().open("google_calendar_secret.p12");
        int size = is.available();
        byte[] buffer = new byte[size];
        is.read(buffer);
        is.close();


        FileOutputStream fos = new FileOutputStream(f);
        fos.write(buffer);
        fos.close();
    }
    catch (Exception e)
    {
        throw new RuntimeException(e);
    }
    return f;
}

一些注意事项:

>确保您正确创建了服务帐户,并且该帐户具有适当的权限:https://developers.google.com/identity/protocols/OAuth2ServiceAccount#delegatingauthority
>确保在后台线程中进行呼叫.如果尝试使用UI线程进行调用,它将失败.
>确保您将项目添加到日历,以便知道它正在工作:)

解决方法:

我不是Android专家,但是以下两种方法均适用于您的用例.

>您的方法:使用服务帐户,将避免让用户对您的应用程序进行身份验证.您可能需要阅读有关“ Delegating domain-wide authority”的信息,这将使您的应用程序可以以您域中的用户(也称为“模拟”用户)进行API调用.我还发现此SO会有所帮助.
>另一种方法:使用Acl.Insert资源.每次用户登录到您的应用程序时,这都需要用户身份验证.这是有关如何实现此功能的example.

从上面的示例源中,将范围设置为Calendar范围而不是SQL Admin,如下所示:

GoogleCredential credential = new GoogleCredential.Builder()
    ...    
      .setServiceAccountScopes(CalendarScopes.CALENDAR)
      .setServiceAccountPrivateKeyFromP12File(xxxx)  
      .build();

希望这会有所帮助,祝你好运!

标签:google-calendar-api,android
来源: https://codeday.me/bug/20191027/1946031.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有