Flutter华为云服务插件huawei_drive的使用

Flutter华为云服务插件huawei_drive的使用

安装

请访问 pub.devAppGallery Connect Configuration 获取安装指南。

文档

额外话题

要求

  • 用户需要一个HUAWEI ID才能访问和管理他们的文件。你的应用需要提示用户使用他们的HUAWEI ID登录,以便他们可以通过你的应用访问他们的Drive。为了使用HUAWEI ID登录,请使用插件 huawei_account。用户登录后,你的应用保存相关的用户信息,以便后续调用Drive SDK API。

示例代码

以下是使用 huawei_drive 插件的完整示例代码:

/*
    Copyright 2021-2023. Huawei Technologies Co., Ltd. All rights reserved.

    Licensed under the Apache License, Version 2.0 (the "License")
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        https://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

import 'dart:typed_data';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:convert';
import 'dart:developer';
import 'dart:io';

import 'package:flutter/foundation.dart';
import 'package:huawei_account/huawei_account.dart';
import 'package:huawei_drive/huawei_drive.dart';
import 'package:huawei_drive_example/custom_widgets/custom_loading.dart';
import 'package:huawei_drive_example/custom_widgets/custom_button.dart';
import 'package:huawei_drive_example/custom_widgets/custom_console.dart';
import 'package:path_provider/path_provider.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  SystemChrome.setPreferredOrientations(<DeviceOrientation>[DeviceOrientation.portraitUp]);
  runApp(const MaterialApp(home: HomeScreenView()));
}

class HomeScreenView extends StatefulWidget {
  const HomeScreenView({Key? key}) : super(key: key);

  [@override](/user/override)
  State<HomeScreenView> createState() => _HomeScreenViewState();
}

class _HomeScreenViewState extends State<HomeScreenView> {
  final List<String> _responsesToDisplay = [];
  bool _isLoading = false;
  final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
  late AccountAuthParamsHelper _helper;
  late AccountAuthService _authService;
  AuthAccount? _account;
  late Drive _drive;
  String? _fileId;
  String? _commentId;
  bool get userLoggedIn => _account != null;

  [@override](/user/override)
  void initState() {
    super.initState();
    _helper = AccountAuthParamsHelper()
      ..setAccessToken()
      ..setId()
      ..setProfile()
      ..setAssistToken()
      ..setAuthorizationCode()
      ..setCarrierId()
      ..setDialogAuth()
      ..setEmail()
      ..setForceLogout()
      ..setIdToken()
      ..setMobileNumber()
      ..setUid()
      ..setScopeList(
        <Scope>[
          Scope.profile,
          Scope.openId,
          Scope.accountBirthday,
          Scope.accountCountry,
          Scope.accountMobileNumber,
          Scope.ageRange,
          Scope.email,
          Scope.game
        ],
        extraScopeURIs: <String>[
          scopeBaseProfile,
          scopeDrive,
          scopeDriveFile,
          scopeDriveReadOnly,
          scopeDriveMetaData,
          scopeDriveMetaDataReadOnly,
          scopeDriveAppData,
        ],
      );
    _authService = AccountAuthManager.getService(_helper.createParams());
    signIn();
    permissionCheck();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      key: _scaffoldKey,
      appBar: AppBar(
        title: const Text('Drive Kit Demo'),
        centerTitle: true,
        backgroundColor: Colors.red,
        actions: _appBarActions(context: context),
      ),
      body: _body(context: context),
    );
  }

  List<Widget> _appBarActions({required BuildContext context}) {
    return userLoggedIn
        ? <Widget>[
            IconButton(
              onPressed: () async {
                await signOut();
              },
              icon: const Icon(Icons.logout_outlined),
            )
          ]
        : <Widget>[];
  }

  Widget _body({required BuildContext context}) {
    return Stack(
      children: [
        userLoggedIn
            ? SingleChildScrollView(
                child: Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.stretch,
                    children: [
                      CustomButton(
                        onPressed: permissionCheck,
                        text: 'Check Permissions',
                      ),
                      CustomButton(
                        onPressed: getAbout,
                        text: 'About',
                      ),
                      CustomButton(
                        onPressed: createFile,
                        text: 'Create File on Drive',
                      ),
                      CustomButton(
                        onPressed: listFiles,
                        text: 'List Files',
                      ),
                      CustomButton(
                        onPressed: updateFileName,
                        text: 'Update File Name',
                      ),
                      CustomButton(
                        onPressed: downloadFile,
                        text: 'Download File to Local Storage',
                      ),
                      CustomButton(
                        onPressed: createComment,
                        text: 'Create Comment',
                      ),
                      CustomButton(
                        onPressed: commentList,
                        text: 'List Comments',
                      ),
                      CustomButton(
                        onPressed: replyComment,
                        text: 'Reply the Comment',
                      ),
                      CustomButton(
                        onPressed: replyList,
                        text: 'List Replies',
                      ),
                      CustomButton(
                        onPressed: batch,
                        text: 'Batch Operations',
                      ),
                      CustomButton(
                        onPressed: deleteFile,
                        text: 'Delete the File',
                      ),
                      CustomButton(
                        onPressed: emptyRecycle,
                        text: 'Empty Recycle Folder',
                      ),
                      CustomConsole(responses: _responsesToDisplay)
                    ],
                  ),
                ),
              )
            : _signInButton(onPressed: signIn),
        _isLoading ? const CustomLoading() : const SizedBox()
      ],
    );
  }

  Widget _signInButton({required AsyncCallback onPressed}) {
    return Center(
      child: CustomButton(
        onPressed: onPressed,
        text: 'Sign In',
      ),
    );
  }

  void showSnackBar(String message) {
    BuildContext? context = _scaffoldKey.currentContext;
    if (context != null) {
      ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(message)));
    }
  }

  Future<void> permissionCheck() async {
    try {
      setLoading(true);

      bool status = await HmsDrivePermissions.requestReadAndWritePermission();
      String response = 'Request Permission State: $status';

      _responsesToDisplay.add(response);
      setLoading(false);
    } catch (e) {
      _displaySnackbar(_SnackbarMessages.defaultError);
    }
  }

  Future<void> signIn() async {
    try {
      setLoading(true);

      _account = await _authService.signIn();
      String? unionId = _account?.unionId;
      RefreshTokenCallback refreshTokenCallback = _refreshToken;
      DriveCredentials deviceCredentials = DriveCredentials(
        unionId: unionId,
        accessToken: _account?.accessToken,
        callback: refreshTokenCallback,
      );
      _drive = await Drive.init(deviceCredentials);
      log('User: ${_account?.displayName}');
      _drive.batch.onBatchResult.listen(_onBatchEvent, onError: _onBatchError);

      setLoading(false);
    } catch (_) {
      _displaySnackbar(_SnackbarMessages.signInError);
    }
  }

  Future<String?> _refreshToken() async {
    _account = await _authService.silentSignIn();
    return _account?.accessToken;
  }

  Future<void> getAbout() async {
    try {
      setLoading(true);
      DriveAbout about = await _drive.about(AboutRequest());
      String response = 'User Display Name: ${about.user?.displayName}';
      _responsesToDisplay.add(response);
      setLoading(false);
    } catch (e) {
      _displaySnackbar(_SnackbarMessages.defaultError);
    }
  }

  Future<void> createFile() async {
    try {
      setLoading(true);
      ByteData byteData = await rootBundle.load('assets/Snake_River_(5mb).jpg');
      Int8List byteArray = byteData.buffer
          .asInt8List(byteData.offsetInBytes, byteData.lengthInBytes);

      DriveFile fileMetadata = DriveFile(
        fileName: 'Snake_River.jpg',
        mimeType: 'image/jpg',
      );

      DriveFileContent fileContent = DriveFileContent(
        type: 'image/jpg',
        byteArray: byteArray,
      );

      DriveFile createdFile = await _drive.files.create(
        FilesRequest.create(
          fileMetadata,
          fileContent: fileContent,
        ),
      );

      _fileId = createdFile.id;
      String response = 'Created Files Name: ${createdFile.fileName}';
      _responsesToDisplay.add(response);
      setLoading(false);
    } catch (e) {
      _displaySnackbar(_SnackbarMessages.defaultError);
    }
  }

  Future<void> listFiles() async {
    try {
      setLoading(true);
      DriveFileList fileList = await _drive.files.list(
        FilesRequest.list(
          fields: '*',
          pageSize: 5,
        ),
      );

      List<String?> fileNames = [];
      for (int i = 0; i < fileList.files.length; i++) {
        log('${fileList.files[i].id} -- ${fileList.files[i].fileName}');
        fileNames.add(fileList.files[i].fileName);
      }
      String response = 'Files on Drive: $fileNames';
      _responsesToDisplay.add(response);
      setLoading(false);
    } catch (e) {
      _displaySnackbar(_SnackbarMessages.defaultError);
    }
  }

  Future<void> updateFileName() async {
    try {
      if (_fileId == null) {
        _displaySnackbar(_SnackbarMessages.fileIdIsNull);
        return;
      }
      setLoading(true);
      DriveFile updatedMetadata = DriveFile(fileName: 'updatedFile.jpg');

      DriveFile updatedFile = await _drive.files
          .update(FilesRequest.update(_fileId, updatedMetadata));

      String response = 'Updated File Name: ${updatedFile.fileName}';

      _responsesToDisplay.add(response);
      setLoading(false);
    } catch (e) {
      _displaySnackbar(_SnackbarMessages.defaultError);
    }
  }

  Future<void> downloadFile() async {
    try {
      final Directory? directory = await getExternalStorageDirectory();
      String? path = directory?.path;
      if (path == null) {
        _displaySnackbar(_SnackbarMessages.downloadPathIsNull);
        return;
      }

      if (_fileId == null) {
        _displaySnackbar(_SnackbarMessages.fileIdIsNull);
        return;
      }
      setLoading(true);
      await _drive.files.getContentAndDownloadTo(
        FilesRequest.getRequest(
          _fileId,
          fields: '*',
        ),
        '$path/downloadedImage.jpg',
      );

      String? response = 'Download Complete.';

      _responsesToDisplay.add(response);
      setLoading(false);
    } catch (e) {
      _displaySnackbar(_SnackbarMessages.defaultError);
    }
  }

  Future<void> createComment() async {
    try {
      if (_fileId == null) {
        _displaySnackbar(_SnackbarMessages.fileIdIsNull);
        return;
      }
      setLoading(true);
      DriveComment comment = DriveComment(
        description: 'This is a comment.',
      );
      DriveComment createdComment = await _drive.comments
          .create(CommentsRequest.create(_fileId, comment));
      _commentId = createdComment.id;
      String? response = 'Comment Added: ${createdComment.description}';

      _responsesToDisplay.add(response);
      setLoading(false);
    } catch (e) {
      _displaySnackbar(_SnackbarMessages.defaultError);
    }
  }

  Future<void> commentList() async {
    try {
      if (_fileId == null) {
        _displaySnackbar(_SnackbarMessages.fileIdIsNull);
        return;
      }
      setLoading(true);
      DriveCommentList commentList =
          await _drive.comments.list(CommentsRequest.list(_fileId));

      List<String?> commentDescriptions = [];
      for (int i = 0; i < commentList.comments.length; i++) {
        commentDescriptions.add(commentList.comments[i].description);
      }
      String? response = 'Comments on File: $commentDescriptions';
      _responsesToDisplay.add(response);
      setLoading(false);
    } catch (e) {
      _displaySnackbar(_SnackbarMessages.defaultError);
    }
  }

  Future<void> replyComment() async {
    try {
      if (_fileId == null || _commentId == null) {
        _displaySnackbar(_SnackbarMessages.fileCommentIdIsNull);
        return;
      }
      setLoading(true);
      DriveReply reply = DriveReply(
        description: 'This is a reply.',
      );
      DriveReply createdReply = await _drive.replies
          .create(RepliesRequest.create(_fileId, _commentId, reply));
      String? response = 'Reply Added: ${createdReply.description}';
      _responsesToDisplay.add(response);
      setLoading(false);
    } catch (e) {
      _displaySnackbar(_SnackbarMessages.defaultError);
    }
  }

  Future<void> replyList() async {
    try {
      if (_fileId == null || _commentId == null) {
        _displaySnackbar(_SnackbarMessages.fileCommentIdIsNull);
        return;
      }
      setLoading(true);
      DriveReplyList replyList =
          await _drive.replies.list(RepliesRequest.list(_fileId, _commentId));
      List<String?> replyDescriptions = [];
      for (int i = 0; i < replyList.replies.length; i++) {
        replyDescriptions.add(replyList.replies[i].description);
      }
      String? response = 'Comments on File: $replyDescriptions';
      _responsesToDisplay.add(response);
      setLoading(false);
    } catch (e) {
      _displaySnackbar(_SnackbarMessages.defaultError);
    }
  }

  Future<void> batch() async {
    try {
      setLoading(true);
      List<Batchable> batchRequests = [
        FilesRequest.create(
          DriveFile(
            fileName: 'sampleFolder',
            mimeType: 'application/vnd.huawei-apps.folder',
          ),
        ),
      ];

      if (_fileId != null) {
        log('here we go');
        batchRequests.add(
          CommentsRequest.create(
            _fileId,
            DriveComment(
              description: 'This is a comment created by batch operation.',
            ),
          ),
        );
      }

      if (_fileId != null && _commentId != null) {
        log('here we go');
        batchRequests.add(
          RepliesRequest.create(
            _fileId,
            _commentId,
            DriveReply(
              description: 'This is a reply created by batch operation.',
            ),
          ),
        );
      }

      await _drive.batch.execute(BatchRequest(batchRequests));
      setLoading(false);
    } catch (e) {
      _displaySnackbar(_SnackbarMessages.defaultError);
    }
  }

  Future<void> deleteFile() async {
    try {
      if (_fileId == null) {
        _displaySnackbar(_SnackbarMessages.fileIdIsNull);
        return;
      }
      setLoading(true);
      bool result = await _drive.files.delete(FilesRequest.delete(_fileId));
      if (!result) {
        String? response = 'Could not delete file.';
        _responsesToDisplay.add(response);
        setLoading(false);
        return;
      }
      _commentId = null;
      _fileId = null;
      String? response = 'Deleted File.';
      _responsesToDisplay.add(response);
      setLoading(false);
    } catch (e) {
      _displaySnackbar(_SnackbarMessages.defaultError);
    }
  }

  Future<void> emptyRecycle() async {
    try {
      setLoading(true);
      bool result =
          await _drive.files.emptyRecycle(FilesRequest.emptyRecycle());
      String? response;
      if (!result) {
        response = 'Could not make recycle folder empty';
      }
      response = 'Emptied Recycle Folder.';
      _responsesToDisplay.add(response);
      setLoading(false);
    } catch (e) {
      _displaySnackbar(_SnackbarMessages.defaultError);
    }
  }

  Future<void> signOut() async {
    try {
      setLoading(true);
      bool didSignOut = await _authService.signOut();
      if (!didSignOut) {
        String message = 'Could not sign out';
        _displaySnackbar(message);
        setLoading(false);
        return;
      }
      bool didCancelAuth = await _authService.cancelAuthorization();
      if (!didCancelAuth) {
        String message = 'Could not cancel authorization';
        _displaySnackbar(message);
        setLoading(false);
        return;
      }
      _account = null;
      setLoading(false);
    } catch (e) {
      _displaySnackbar(_SnackbarMessages.defaultError);
    }
  }

  void setLoading(bool loading) {
    setState(() {
      _isLoading = loading;
    });
  }

  void _displaySnackbar(String message) {
    setLoading(false);
    showSnackBar(message);
  }

  void _onBatchError(Object error) {
    if (error is PlatformException) {
      log("BatchError: ${jsonDecode(error.message ?? "")}");
    }
  }

  void _onBatchEvent(dynamic event) {
    String message = 'Batch Operation - Success';
    setState(() {
      _responsesToDisplay.add(message);
    });
  }
}

extension _SnackbarMessages on HomeScreenView {
  static const String fileIdIsNull = 'FileId is empty. Please create a file.';
  static const String fileCommentIdIsNull =
      'Either file or comment id is empty. Please create a comment on created file.';
  static const String downloadPathIsNull = 'Downloads directory path is null';
  static const String defaultError = 'Operation could not succeed';
  static const String signInError = 'Could not sign in';
}

更多关于Flutter华为云服务插件huawei_drive的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter华为云服务插件huawei_drive的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


华为云服务插件 huawei_drive 是华为为 Flutter 开发者提供的一个插件,用于在应用程序中集成华为云盘(Huawei Drive)的功能。通过这个插件,开发者可以方便地在 Flutter 应用中实现文件的上传、下载、管理等操作。

以下是如何在 Flutter 项目中使用 huawei_drive 插件的基本步骤:

1. 添加依赖

首先,在 pubspec.yaml 文件中添加 huawei_drive 插件的依赖:

dependencies:
  huawei_drive: ^6.4.0+300

然后运行 flutter pub get 来获取依赖。

2. 配置华为开发者账号

在使用 huawei_drive 插件之前,你需要在华为开发者网站上注册账号并创建一个项目。然后,启用华为云盘(Huawei Drive)服务,并获取 App IDApp Secret

3. 初始化 Huawei Drive

在你的 main.dart 文件中初始化 Huawei Drive 插件:

import 'package:huawei_drive/huawei_drive.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  // 初始化 Huawei Drive
  await DriveClient.init(
    appId: 'your_app_id',
    appSecret: 'your_app_secret',
  );
  
  runApp(MyApp());
}

4. 用户授权

在访问华为云盘之前,用户需要进行授权。你可以使用 DriveAuth 类来实现用户授权:

import 'package:huawei_drive/huawei_drive.dart';

Future<void> authorizeUser() async {
  try {
    await DriveAuth.signIn();
    print('User authorized successfully');
  } catch (e) {
    print('Authorization failed: $e');
  }
}

5. 上传文件

使用 DriveClient 类来上传文件到华为云盘:

import 'package:huawei_drive/huawei_drive.dart';

Future<void> uploadFile() async {
  final driveClient = DriveClient();
  final file = File('/path/to/local/file.txt');
  
  try {
    final driveFile = await driveClient.uploadFile(
      file,
      parentFolderId: 'root', // 上传到根目录
      fileName: 'file.txt',
    );
    print('File uploaded successfully: ${driveFile.id}');
  } catch (e) {
    print('File upload failed: $e');
  }
}

6. 下载文件

使用 DriveClient 类来下载文件:

import 'package:huawei_drive/huawei_drive.dart';

Future<void> downloadFile() async {
  final driveClient = DriveClient();
  const fileId = 'your_file_id';
  const savePath = '/path/to/save/file.txt';
  
  try {
    await driveClient.downloadFile(fileId, savePath);
    print('File downloaded successfully');
  } catch (e) {
    print('File download failed: $e');
  }
}

7. 管理文件

你可以使用 DriveClient 类来列出、删除、移动文件等操作。例如,列出根目录下的所有文件:

import 'package:huawei_drive/huawei_drive.dart';

Future<void> listFiles() async {
  final driveClient = DriveClient();
  
  try {
    final fileList = await driveClient.listFiles(folderId: 'root');
    for (var file in fileList) {
      print('File: ${file.fileName}, ID: ${file.id}');
    }
  } catch (e) {
    print('Failed to list files: $e');
  }
}

8. 处理权限

华为云盘提供了强大的权限管理功能。你可以使用 DrivePermissions 类来管理文件的权限:

import 'package:huawei_drive/huawei_drive.dart';

Future<void> managePermissions() async {
  final driveClient = DriveClient();
  const fileId = 'your_file_id';
  
  try {
    await driveClient.grantPermission(fileId, permission: DrivePermission.read);
    print('Permission granted successfully');
  } catch (e) {
    print('Permission grant failed: $e');
  }
}
回到顶部