使用 Google 相册和 Flutter 构建照片分享应用

构建内容

在本 Codelab 中,您将构建供用户分享照片的郊游应用 Field Trippa。

了解如何借助 Google Photos Library API 在自己的应用中支持媒体内容分享体验。

本 Codelab 的应用是使用 Flutter 构建的。Flutter 是 Google 的界面工具包,用于利用单一代码库为移动设备、网页和桌面设备构建精巧的原生编译应用。如需了解详情,请访问 https://flutter.dev

6571e359f222ccf6.png

学习内容

所需条件

  • Flutter 开发环境
  • 在不同的模拟器或设备上设置两个可访问 Google 相册的 Google 用户帐号,以便您可以测试在用户之间分享内容
  • 1 台 Android 设备、模拟器或 iOS 实体设备 - 因缺少相机硬件,暂不支持 iOS 模拟器

在本 Codelab 中,您将使用 Google Photos Library API 构建一个用于分享远足或郊游照片的应用。

用户将使用 Google 登录功能登录帐号,并授权应用使用 Google Photos Library API。

然后,用户便可以创建一个 trip,用于上传附带说明的照片。每个 trip 都可与应用的其他用户共享,这些用户也可以贡献照片。

146953eced1f4f92.png

在后台,每个 trip 都会以共享影集的形式存储在 Google 相册中。该应用可处理向此影集分享和上传照片的操作,您也可以通过分享 Google 相册的网址,向没有安装该应用的用户直接分享影集。

c4af82aa4bf8cc31.png

您想通过本 Codelab 学习哪些内容?

我不熟悉这个主题,想大致了解一下。 我对这个主题有所了解,但我想重温一下。 我在寻找示例代码以用到我的项目中。 我在寻找有关特定内容的说明。

b2f84ff91b0e1396.png下载本 Codelab 的源代码:

下载源代码 在 GitHub 上浏览

(应用起始代码位于代码库中的 main 分支中)。

解压下载的 ZIP 文件。这将创建一个根文件夹 photos-sharing-main,其中包含您顺利上手所需的所有代码和资源。

在您的首选 Flutter IDE(例如已安装 Dart 和 Flutter 插件的 VSCode 或 Android Studio)中打开解压缩的文件夹。

最终实现代码

以下链接指向完全实现的最终版应用。如果您遇到困难或想要比较您的实现时,可以参阅此代码:

下载最终源代码 在 GitHub 上浏览最终源代码

(最终版应用代码位于代码库中的 final 分支中)。

如果您之前未曾使用过 Flutter 进行开发,请按照这些步骤设置开发环境

如需运行“Field Trippa”应用,请在您的开发 IDE 中点击“run”(运行)按钮,或从源代码的根目录运行以下命令:

flutter run

您应该会看到 Connect with Google Photos 屏幕:

6bfc7e3fab746b8d.png

Google Photos Library API 会要求您使用 OAuth 2.0 对用户进行身份验证。用户登录应用并授权该应用代表自己与该 API 进行交互。

您可在此步骤的末尾找到更多问题排查提示。

创建新的 Firebase 项目并注册您的应用

b2f84ff91b0e1396.png 转到 Firebase 控制台,然后选择“+ 添加项目”。输入项目名称,然后选择“创建项目”以继续。不要在 Firebase 控制台中执行任何其他步骤,而请返回到本 Codelab 并继续执行下面的“Android”或“iOS”部分以配置应用。

仅限 Android:如果您是在 Android 上运行应用,请注册 Android 应用

b2f84ff91b0e1396.png 点击 Android 图标以打开 Android 应用注册屏幕。

b2f84ff91b0e1396.png 对于 package,请输入:com.google.codelab.photos.sharing

b2f84ff91b0e1396.png 从您的计算机中检索签名证书 SHA-1

在 Windows 上,请运行以下命令:

keytool -alias androiddebugkey -keystore %USERPROFILE%\.android\debug.keystore -list -v -storepass android

在 Mac 或 Linux 上,请运行以下命令:

keytool -alias androiddebugkey -keystore ~/.android/debug.keystore -list -v -storepass android

b2f84ff91b0e1396.png 点击“register app”以继续。

b2f84ff91b0e1396.pnggoogle-service.json 文件下载到您的计算机中,并将其移至目录“android/app/”下。(提示:在 Android Studio 中,您可以将已下载的文件直接拖放到 project 侧边栏中的正确位置。)

此文件包含您刚刚设置的 Firebase 和 Google Developers 项目的项目配置。

(如需了解详情,请参阅软件包 google_sign_in 的文档。)

您无需在 Firebase 控制台中完成任何其他步骤。Firebase SDK 已添加到应用中。

仅限 iOS:如果您是在 iOS 上运行应用,请在 Firebase 中注册 iOS 应用

b2f84ff91b0e1396.png 点击 iOS 图标以打开 iOS 应用注册屏幕。

b2f84ff91b0e1396.png 对于 iOS bundle ID,请输入:com.google.codelab.photos.sharing

b2f84ff91b0e1396.png 点击 next 以继续。

b2f84ff91b0e1396.pngGoogleService-Info.plist 文件下载到计算机上。

b2f84ff91b0e1396.png 在 Xcode 中打开相应 Flutter 项目

b2f84ff91b0e1396.png 右键点击 Runner 目录,选择 Add Files to Runner,然后选择您已下载的 GoogleService-Info.plist 文件,将其添加到 Runner 模块中。

b2f84ff91b0e1396.png 修改 ios/Runner/Info.plist 文件的源代码,然后为文件 GoogleService-Info.plist 中的属性 REVERSED_CLIENT_ID 添加值。替换文件底部的条目:

ios/Runner/Info.plist

<!-- Google Sign-in Section -->
<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleTypeRole</key>
    <string>Editor</string>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>COPY_REVERSED_CLIENT_ID_HERE</string>
    </array>
  </dict>
</array>
<!-- End of the Google Sign-in Section -->

(如需了解详情,请参阅软件包 google_sign_in 的文档。)

启用 Google Photos Library API

b2f84ff91b0e1396.png 在 Google Developers Console 中打开 API 屏幕,然后启用 Google Photos Library API。(如果 enable 按钮处于停用状态,您必须先在屏幕顶部选择 Firebase 项目。)

b2f84ff91b0e1396.png 在 Google Developers Console 中打开 OAuth 同意屏幕配置,添加 Google Photos Library API 作用域和您的电子邮件地址。(对于 Google Photos Library API 使用的任何作用域,OAuth 验证审核都需要此配置。)您可以不必提交进行验证,但需要填写表单并保存您的回复。此操作将针对开发和测试启用作用域。

  • 输入应用名称,例如 Field Trippa Codelab
  • 选择支持服务电子邮件地址
  • 选择添加作用域,然后选择手动添加以粘贴作用域,输入以下作用域:
https://www.googleapis.com/auth/photoslibrary
https://www.googleapis.com/auth/photoslibrary.sharing
  • 选择保存
  • 无需提交进行验证也能继续进行本 Codelab 的学习。仅当发布应用时才需要提交进行验证,个人测试时无需提交验证。

运行应用并登录

Google 登录功能已使用 google_sign_in flutter 软件包实现。此软件包需要您已复制到项目中的 google-services.jsonGoogleService-Info.plist 文件。

b2f84ff91b0e1396.png 再次运行应用,然后选择 Connect to Google Photos。系统会提示您选择用户帐号并接受身份验证作用域。

正确设置各项内容后,您会在下一个屏幕上看到一个空列表。

9f3bcae1f8e7cd0d.png

排查登录问题

如果您在登录应用时遇到问题,请检查以下几个方面:

b2f84ff91b0e1396.png 检查设备是否已连接到互联网。

b2f84ff91b0e1396.png 如果您收到 PlatformException(sign_in_failed, com.google.android.gms.common.api.ApiException: 10: , null) 错误,请确保已完成“启用 Google Photos Library API”部分中的所有步骤。您必须添加 Google Photos Library API 作用域,输入支持服务电子邮件地址,然后选择保存

b2f84ff91b0e1396.png 如果您收到 r PlatformException(sign_in_failed, com.google.android.gms.common.api.ApiException: 12500: , null) 错误,请确保您已在 Firebase 控制台中添加支持服务电子邮件地址。打开 Firebase 控制台,选择相应项目名称旁边的齿轮图标以进入项目设置。在常规设置屏幕上的支持电子邮件地址下,选择一个电子邮件地址。

b2f84ff91b0e1396.png 检查在 Firebase 控制台中配置的签名证书 SHA-1。它与第一步中的 keytool 命令的输出是否匹配?它与在 android/ 项目中运行命令 ./gradlew signingReport 时的输出是否匹配?您可能还需要在控制台中添加签名证书 SHA-256

b2f84ff91b0e1396.png 检查在 Firebase 控制台中配置的软件包名称iOS 软件包 ID。应将其设置为 com.google.codelab.photos.sharing

b2f84ff91b0e1396.png 检查您从 Firebase 控制台中下载的配置文件的位置。对于 Android,文件应复制到 android/app/google-service.json。对于 iOS,文件应添加到 Runner 模块中。

b2f84ff91b0e1396.png 您可能需要启用 Google 作为 Firebase 项目的登录服务提供方。打开 Firebase 控制台,然后导航到身份验证登录方法。确保已启用 Google

在实现对 Google Photos Library API 的首次 API 调用之前,我们先来了解一下“Field Trippa”应用采用的数据架构。

应用架构

  • 每个屏幕均实现为一个单独的页面:71b9a588fb1bbb41.png
  • PhotosLibraryApiModel 描述应用的数据模型,并抽象化处理 Google Photos Library API 调用。
  • 对 Library API 的 HTTPS REST 调用在 PhotosLibraryApiClient 中实现。此类提供的每个调用均采用 *Request 对象,您可以在该对象中指定调用的参数和选项。
  • Library API 要求通过 OAuth2 对用户进行身份验证。所有 API 调用中都必须包含的访问令牌由 PhotosLibraryApiClient 上的 google_sign_in 软件包直接设置。

实现创建影集 API 调用

每个行程都会以影集的形式存储在 Google 相册中。当您选择 CREATE A TRIP ALBUM 按钮时,系统会提示您输入行程的名称,并创建同名新影集。

b2f84ff91b0e1396.pngcreate_trip_page.dart 中,编写向 Library API 发出创建影集的请求的逻辑。在文件末尾实现 _createTrip(...) 方法,以使用用户输入的行程名称调用 PhotosLibraryApiModel

lib/pages/create_trip_page.dart

Future<void> _createTrip(BuildContext context) async {
  // Display the loading indicator.
  setState(() => _isLoading = true);

  await ScopedModel.of<PhotosLibraryApiModel>(context)
      .createAlbum(tripNameFormController.text);

  // Hide the loading indicator.
  setState(() => _isLoading = false);
  Navigator.pop(context);
}

b2f84ff91b0e1396.png 实现创建影集的 Library API 调用。在 API 模型中,实现 createAlbum(...) 方法,此方法将使用影集名称作为参数。它会向 PhotosLibraryApiClient 发出调用,这里实际会进行 REST 调用。

lib/model/photos_library_api_model.dart

Future<Album> createAlbum(String title) async {
  final album = await client.createAlbum(CreateAlbumRequest.fromTitle(title));
  updateAlbums();
  return album;
}

b2f84ff91b0e1396.png 实现 REST 调用以在 photos_library_api_client.dart 中创建影集。请注意,CreateAlbumRequest 已包含此调用所需的 title 属性。

以下示例将此过程编码为 JSON,并添加身份验证标头来为请求授权。最后,返回 API 创建的影集。

lib/photos_library_api/photos_library_api_client.dart

Future<Album> createAlbum(CreateAlbumRequest request) async {
  final response = await http.post(
    Uri.parse('https://photoslibrary.googleapis.com/v1/albums'),
    body: jsonEncode(request),
    headers: await _authHeaders,
  );

  printError(response);

  return Album.fromJson(jsonDecode(response.body));
}

试试看!

b2f84ff91b0e1396.png 部署应用,然后选择 + Create Trip

2f0bec785bec1710.gif

您可能已经注意到行程列表中还显示了来自 Google 相册但并不是由您的应用所创建的其他影集。(如果您在 Google 相册中没有其他影集,但想要看到这种情况,请打开 Google 相册应用并创建一个影集。不过,本 Codelab 并不要求执行此操作。)

请记住,每个行程都以影集的形式存储在 Google 相册中。不过,在这里显示 Google 相册中通过其他方式创建的任何其他影集是没有意义的,Field Trippa 应仅显示由该应用创建的行程。

您可以使用 API 来限制所显示的行程列表,使其仅显示由该应用创建的行程。

b2f84ff91b0e1396.pngphotos_library_api_client.dart 中修改 listAlbums() 方法(不是 listSharedAlbums()!)。此方法会发出 REST 调用以检索影集列表。添加参数 excludeNonAppCreatedData=true,使返回的数据排除并非由此应用创建的影集。

lib/photos_library_api/photos_library_api_client.dart

Future<ListAlbumsResponse> listAlbums() async {
  final response = await http.get(
        Uri.parse('https://photoslibrary.googleapis.com/v1/albums?'
            'pageSize=50&excludeNonAppCreatedData=true'),
        headers: await _authHeaders);

       ...
}

试试看!

现在,第一个页面仅显示由该应用创建的行程。

c7c20b76dcbfbfea.png

下一步是上传照片到行程。这些数据存储在用户的 Google 相册帐号中,因此您无需担心存储空间不够或要自己处理数据。

在 Flutter 中拍摄照片

b2f84ff91b0e1396.png 首先,在贡献照片对话框中实现 _getImage(...) 方法。当用户点击 +ADD PHOTO 按钮时,系统会调用此方法。

以下代码使用 image_picker 软件包拍摄照片,更新界面并调用 API 模型来上传该照片。(您将在下一步中实现此操作。)_getImage(...) 调用会存储上传令牌,以便稍后用于在 Google 相册中创建相应照片。

lib/components/contribute_photo_dialog.dart

Future _getImage(BuildContext context) async {
  // Use the image_picker package to prompt the user for a photo from their
  // device.
  final pickedImage = await _imagePicker
      .getImage(
        source: ImageSource.camera,
      );
  final pickedFile = File(pickedImage.path);

  // Store the image that was selected.
  setState(() {
    _image = pickedFile;
    _isUploading = true;
  });

  // Make a request to upload the image to Google Photos once it was selected.
  final uploadToken = await ScopedModel.of<PhotosLibraryApiModel>(context)
      .uploadMediaItem(pickedFile);

  setState(() {
    // Once the upload process has completed, store the upload token.
    // This token is used together with the description to create the media
    // item later.
    _uploadToken = uploadToken;
    _isUploading = false;
  });
}

实现上传照片以获取上传令牌的 Library API 调用

上传照片和视频到 Library API 的过程分为两个步骤:

  1. 上传媒体内容以接收上传令牌
  2. 使用该上传令牌在用户的内容库中创建媒体内容

b2f84ff91b0e1396.png 实现上传媒体内容的 REST 请求。您需要设置一些标头来指定上传请求的类型和相应文件名。在 photos_library_api_client.dart 文件中,实现用于上传文件的 uploadMediaItem(...) 方法,从而返回相应 HTTP 调用返回的上传令牌:

lib/photos_library_api/photos_library_api_client.dart

Future<String> uploadMediaItem(File image) async {
  // Get the filename of the image
  final filename = path.basename(image.path);

  // Set up the headers required for this request.
  final headers = <String, String>{};
  headers.addAll(await _authHeaders);
  headers['Content-type'] = 'application/octet-stream';
  headers['X-Goog-Upload-Protocol'] = 'raw';
  headers['X-Goog-Upload-File-Name'] = filename;

  // Make the HTTP request to upload the image. The file is sent in the body.
  final response = await http.post(
    Uri.parse('https://photoslibrary.googleapis.com/v1/uploads'),
    body: image.readAsBytesSync(),
    headers: await _authHeaders,
  );

  printError(response);

  return response.body;
}

使用上传令牌创建媒体内容

接下来,使用该上传令牌在用户的内容库中创建媒体内容。

创建媒体内容需要上传令牌、可选说明(例如照片或视频的说明)以及影集的可选标识符。Field Trippa 始终会将上传的照片直接添加到行程影集中。

b2f84ff91b0e1396.png 实现对的 photos_library_api_client 调用,该调用会使用上传令牌、说明和影集 ID 调用 mediaItems.batchCreate。在 API 模型中,实现 createMediaItem(...) 方法以调用 Library API。此方法将返回媒体内容。

(此调用的 photos_library_client 已实现。)

lib/model/photos_library_api_model.dart

Future<BatchCreateMediaItemsResponse> createMediaItem(
    String uploadToken, String albumId, String description) async {
  // Construct the request with the token, albumId and description.
  final request =
      BatchCreateMediaItemsRequest.inAlbum(uploadToken, albumId, description);

  // Make the API call to create the media item. The response contains a
  // media item.
  final response = await client.batchCreateMediaItems(request);

  // Print and return the response.
  print(response.newMediaItemResults[0].toJson());
  return response;
}

试试看!

b2f84ff91b0e1396.png打开应用并选择一个行程。点击 contribute,然后选择您之前拍摄的照片。输入说明并选择 upload。图片应在几秒钟后出现在行程中。

b2f84ff91b0e1396.png 在 Google 相册应用中打开影集 - 您会在此行程的影集中看到这张新图片。

526ede994fcd5d8d.gif

到目前为止,您已实现了以下功能:创建行程并向行程上传带有说明的照片。在后端,每个行程都以影集的形式存储在 Google 相册中。

接下来,您将向未使用应用的用户分享行程。

每个行程都由 Google 相册中的相应影集提供支持,因此您可以通过网址“分享”影集,让每个拥有此网址的人都可以访问该影集。

实现分享影集的调用

当用户按下影集顶部的 share 按钮时,系统会通过行程页面分享影集。

b2f84ff91b0e1396.png 实现异步调用 _shareAlbum(...),以此调用模型来分享影集,然后重新加载所显示的影集。通过重新加载影集,可以传递 shareInfo 属性,其中包含您稍后将在对话框中向用户显示的 shareableUrl

lib/pages/trip_page.dart

Future<void> _shareAlbum(BuildContext context) async {
  // Show the loading indicator
  setState(() => _inSharingApiCall = true);

  const snackBar = SnackBar(
    duration: Duration(seconds: 3),
    content: Text('Sharing Album...'),
  );
  Scaffold.of(context).showSnackBar(snackBar);

  // Share the album and update the local model
  await ScopedModel.of<PhotosLibraryApiModel>(context).shareAlbum(album.id);
  final updatedAlbum =
      await ScopedModel.of<PhotosLibraryApiModel>(context).getAlbum(album.id);

  print('Album has been shared.');
  setState(() {
    album = updatedAlbum;
    // Hide the loading indicator
    _inSharingApiCall = false;
  });
}

b2f84ff91b0e1396.png 实现 _showShareableUrl(...) 方法,用户点击页面顶部的 SHARE WITH ANYONE 按钮时,系统会调用此方法。首先,检查影集是否已分享,如果已分享,则调用 _showUrlDialog(...) 方法。

lib/pages/trip_page.dart

Future<void> _showShareableUrl(BuildContext context) async {
  if (album.shareInfo == null || album.shareInfo.shareableUrl == null) {
    print('Not shared, sharing album first.');
    // Album is not shared yet, share it first, then display dialog
    await _shareAlbum(context);
    _showUrlDialog(context);
  } else {
    // Album is already shared, display dialog with URL
    _showUrlDialog(context);
  }
}

b2f84ff91b0e1396.png 实现 _showUrlDialog(...) 方法,以便在对话框中显示 shareableUrl

lib/pages/trip_page.dart

void _showUrlDialog(BuildContext context) {
  print('This is the shareableUrl:\n${album.shareInfo.shareableUrl}');

  _showShareDialog(
      context,
      'Share this URL with anyone. '
      'Anyone with this URL can access all items.',
      album.shareInfo.shareableUrl);
}

试试看!

该应用仅会在主屏幕上列出尚未分享的行程。不用担心,我们会在下一步中实现此功能。现在,如果您退出该屏幕,您可以创建一个新的行程。

b2f84ff91b0e1396.png 打开应用并选择一个行程。选择屏幕顶部的 SHARE WITH ANYONE,然后在浏览器中打开返回的网址。(提示:此网址也会输出到日志中,以便您轻松地在计算机上复制此网址。在 Android Studio 中,日志会显示在 Run 标签页中。)

1d1a40c1078e4221.gif

在 Google 相册中,可以通过网址分享影集,任何有权访问该网址的人都可以查看该影集。借助 Library API,您也可以通过分享令牌分享影集。分享令牌是应用内使用的字符串,该字符串用于通过 API 将用户加入共享影集。

应用通过 Library API 分享影集的过程如下所示:

  1. 用户 A 登录您的应用并为 Library API 授权
  2. 创建影集
  3. 使用影集的标识符分享影集
  4. 将分享令牌分享给其他用户

加入过程与此类似:

  1. 用户 B 登录您的应用并为 Library API 授权
  2. 检索用户应加入的影集的分享令牌
  3. 使用该分享令牌加入影集

共享影集会显示在 Google 相册的“Sharing”标签页上。

显示分享令牌

在上一步中,您已经实现了分享影集的 _shareAlbum(...) 方法。shareInfo 属性还包含将显示在屏幕上的“分享令牌”

b2f84ff91b0e1396.png 在行程页面上,实现 _showShareToken(...) 方法,当用户按屏幕上的 SHARE WITH FIELD TRIPPA 按钮时,系统会调用此方法。

lib/pages/trip_page.dart

Future<void> _showShareToken(BuildContext context) async {
  if (album.shareInfo == null) {
    print('Not shared, sharing album first.');
    // Album is not shared yet, share it first, then display dialog
    await _shareAlbum(context);
    _showTokenDialog(context);
  } else {
    // Album is already shared, display dialog with token
    _showTokenDialog(context);
  }
}

接下来,在 _showTokenDialog(...) 方法中实现“分享令牌”的显示。此令牌是影集的 shareInfo 属性的一部分。

lib/pages/trip_page.dart

void _showTokenDialog(BuildContext context) {
  print('This is the shareToken:\n${album.shareInfo.shareToken}');
  _showShareDialog(
      context, 'Use this token to share', album.shareInfo.shareToken);
}

列出共享影集

此应用目前仅会列出用户拥有的影集,而非共享影集。

只有由用户创建或明确添加到其 Google 相册库的影集才会显示在 Google 相册应用的“影集”屏幕上。在 Library API 中调用 albums.list 时,系统只会返回这些影集。不过,在我们的应用中,用户可以加入其他用户的共享影集,这些影集仅会在列出共享影集的调用中返回。您需要更改从 Library API 检索行程列表(影集)的方式,以便同时包含用户创建的影集和共享影集。

b2f84ff91b0e1396.png 影集将在 API 模型中加载并缓存。更改模型中的 updateAlbums() 实现,以加载用户创建的影集和共享影集,然后将它们存储为一个列表。

此实现使用多个 Future 以异步方式列出影集,然后将它们合并到缓存影集列表中。删除旧实现并注释掉新代码。

lib/model/photos_library_api_model.dart

void updateAlbums() async {
  // Reset the flag before loading new albums
  hasAlbums = false;
  // Clear all albums
  _albums.clear();
  // Skip if not signed in
  if (!isLoggedIn()) {
    return;
  }
  // Add albums from the user's Google Photos account
  // var ownedAlbums = await _loadAlbums();
  // if (ownedAlbums != null) {
  //   _albums.addAll(ownedAlbums);
  // }

  // Load albums from owned and shared albums
  final list = await Future.wait([_loadSharedAlbums(), _loadAlbums()]);

  _albums.addAll(list.expand((a) => a ?? []));

  notifyListeners();
  hasAlbums = true;
}

加入共享影集

您可以使用分享令牌将应用的用户加入影集。在本 Codelab 中,此功能通过一个简单的文本对话框实现。

b2f84ff91b0e1396.png 在加入行程页面上实现 _joinTrip 方法,该方法使用用户输入的分享令牌调用 API 模型。首先,显示加载指示器,接着使用文本格式的输入发出加入共享影集的调用,然后隐藏加载指示器并返回上一个屏幕。

lib/pages/join_trip_page.dart

Future<void> _joinTrip(BuildContext context) async {
  // Show loading indicator
  setState(() => _isLoading = true);

  // Call the API to join an album with the entered share token
  await ScopedModel.of<PhotosLibraryApiModel>(context)
      .joinSharedAlbum(shareTokenFormController.text);

  // Hide loading indicator
  setState(() => _isLoading = false);

  // Return to the previous screen
  Navigator.pop(context);
}

试试看!

要尝试进行 Codelab 这一部分的操作,您需要用另一个用户帐号登录另一个设备或模拟器。

b2f84ff91b0e1396.png 用一个用户帐户创建并分享行程,然后选择 SHARE IN FIELD TRIPPA 选项,以检索分享令牌。将此分享令牌复制到另一个设备或模拟器,并通过首页上的 JOIN A TRIP ALBUM 选项输入此令牌。(提示:在模拟器和主机之间剪贴板是共享的。)

8043086cc00eaa16.gif 55c1e75014d4d2a4.gif

实际实现提示

在实际应用(而非 Codelab)中实现分享功能时,您应该仔细考虑如何使用分享令牌将用户加入影集。您不妨考虑将令牌存储在您的安全后端,并借助用户之间的关系创建并加入影集。

例如,足球俱乐部聚会应用可以跟踪特定计划活动的参与者,并且仅在提示参与者之后才将他们加入影集。

在对用户的 Google 相册帐号进行任何更改之前,请务必告知用户并请求其同意。如需了解详情,请参阅 Google Photos Library API 用户体验指南

您已构建的内容

  • 在您的应用中实现了由 Google 相册提供支持的分享功能
  • 利用 Google Photos Library API 创造自己的照片和视频分享体验,而无需担心基础架构或存储空间的问题
  • 以有趣而新颖的方式利用 API 中的共享功能将内容直接分享给用户。
  • 使用了 Library API 的一些关键部分:
  • 创建了新影集并上传了新照片
  • 列出了共享影集,并限制仅列出由您的应用创建的影集

下一步做什么

请参阅 Google Photos API 的开发者文档(网址:https://developers.google.com/photos),详细了解分享媒体内容的方法以及 Library API 的其他部分。例如,由机器学习提供支持的智能内容过滤器可帮您找到合适的照片和视频。

当您准备好发布您的集成时,可以加入 Google 相册合作伙伴计划

请注意参考用户体验指南技术最佳做法。为了帮助您顺利上手,我们还提供了部分语言版本的客户端库