Overview

HMS Core Drive SDK allows you to create apps that use the HUAWEI Drive Kit service. HUAWEI Drive Kit provides cloud storage for your apps, enabling users to store files that are created when using your apps, including photos, videos, and documents, in HUAWEI Drive (Drive for short), as well as download and synchronize these files on demand. HUAWEI Drive Kit also provides comprehensive data protection, empowering users to manage their data securely and conveniently.
The current core capabilities include uploading, downloading, searching for, and commenting on files in Drive, replying to comments, querying file changes, and obtaining notifications.

What You Will Create

In this codelab, you will create an Android app that is capable of using HUAWEI Drive Kit. By integrating Drive Kit into your app, the app will allow users to manage and edit files in Drive with optimal convenience, with the ability to store photos, drawings, recordings, videos, and designs in Drive, and access files in Drive from any smartphone, tablet, or computer.

What You Will Learn

What You Will Need

Hardware Requirements

Software Requirements

To integrate HUAWEI HMS Core, you must complete the following preparations:

For details, please refer to Preparations for Integrating HUAWEI HMS Core.

Enabling Related Services

Go to My projects > Project Setting > Manage APIs.

Toggle the Account Kit and Drive Kit switches.

Adding the Configuration File

Adding the agconnect-services.json File of the App

  1. In HUAWEI Developers AppGallery Connect, click the app that you have created and go to My projects > Project Setting General information. In the Project area, click Set.
  2. Set the app data storage location, and click OK.
  3. In the App information area, click agconnect-services.json to download the configuration file.
  4. Copy the agconnect-services.json file to the app's root directory.

Adding Build Dependencies

1. Open the build.gradle file in the app directory.

2. Configure build dependencies.

dependencies { implementation 'com.huawei.hms:drive:5.0.0.300' implementation 'com.huawei.hms:hwid:4.0.0.300' }

3. Open the modified build.gradle file. You will find a Sync Now link in the upper right corner of the page. Click Sync Now and wait until synchronization is complete.

4. Define multi-language settings.

● Skip this step if your app does not require support for additional languages. By default, your app supports all languages provided by the HMS Core SDK.

● If your app uses only some of these languages, follow the operation procedure in this section to complete the required configuration.

Open the build.gradle file in the app directory of your project.

Go to android > defaultConfig and add the resConfigs configuration. For example, if your app supports only English and Simplified Chinese, the configuration is as follows:

android { defaultConfig { ... resConfigs "en", "zh-rCN" } }

Configuring Obfuscation Scripts

Before building the APK, configure obfuscation scripts to prevent the HMS Core SDK from being obfuscated. If obfuscation arises, the HMS Core SDK may not function properly.

1. Open the obfuscation configuration file proguard-rules.pro of your Android project.

2. Add configurations to exclude the HMS Core SDK from obfuscation.

-ignorewarning -keepattributes *Annotation* -keepattributes Exceptions -keepattributes InnerClasses -keepattributes Signature -keepattributes SourceFile,LineNumberTable -keep class com.hianalytics.android.**{*;} -keep class com.huawei.updatesdk.**{*;} -keep class com.huawei.hms.**{*;} -keep class com.huawei.cloud.services.drive.**{*;}

3. If you are using AndResGuard, add it to the allowlist in the obfuscation script file.

"R.string.hms*", "R.string.connect_server_fail_prompt_toast", "R.string.getting_message_fail_prompt_toast", "R.string.no_available_network_prompt_toast", "R.string.third_app_*", "R.string.upsdk_*", "R.layout.hms*", "R.layout.upsdk_*", "R.drawable.upsdk*", "R.color.upsdk*", "R.dimen.upsdk*", "R.style.upsdk*", "R.string.agc*"

Signing In with a HUAWEI ID

Handling a LOGIN Button Event

To implement the sign-in function through the HMS Core SDK, you will need to set the Drive scope for obtaining the permission to access Drive APIs.

private void driveLogin() { AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); List<Scope> scopeList = new ArrayList<>(); scopeList.add(new Scope(DriveScopes.SCOPE_DRIVE));// All permissions, except permissions for the app data folder. scopeList.add(new Scope(DriveScopes.SCOPE_DRIVE_READONLY));// Permissions to view file metadata and content. scopeList.add(new Scope(DriveScopes.SCOPE_DRIVE_FILE));// Permissions to view and manage files. scopeList.add(new Scope(DriveScopes.SCOPE_DRIVE_METADATA)); // Permissions to view and manage file metadata, excluding file content. scopeList.add(new Scope(DriveScopes.SCOPE_DRIVE_METADATA_READONLY));// Permissions to view file metadata, excluding file content. scopeList.add(new Scope(DriveScopes.SCOPE_DRIVE_APPDATA)); // Permissions to upload and store app data. scopeList.add(HuaweiIdAuthAPIManager.HUAWEIID_BASE_SCOPE); // Basic account permissions. HuaweiIdAuthParams authParams = new HuaweiIdAuthParamsHelper(DEFAULT_AUTH_REQUEST_PARAM) .setAccessToken() .setIdToken() .setScopeList(scopeList) .createParams(); // Call the account API to obtain account information. HuaweiIdAuthService client = HuaweiIdAuthManager.getService(this, authParams); startActivityForResult(client.getSignInIntent(), REQUEST_SIGN_IN_LOGIN); }

Each Drive scope corresponds to a certain type of permissions. You may apply for the permissions as needed. For details about the corresponding APIs, please refer to HUAWEI Account Kit Development Guide. If the app user has not signed in with a HUAWEI ID, the HMS Core SDK will prompt the user to sign in.

private DriveCredential.AccessMethod refreshAT = new DriveCredential.AccessMethod() { // Simplified code snippet for demonstration purposes. For the complete code snippet, please go to Client Development > Obtaining Authentication Information > Save authentication information in the HUAWEI Drive Kit Development Guide. @Override public String refreshToken() { return accessToken; } }; // Abnormal process for obtaining account information. Obtain and save the related accessToken and unionID using this function. @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); Log.i(TAG, "onActivityResult, requestCode = " + requestCode + ", resultCode = " + resultCode); if (requestCode == REQUEST_SIGN_IN_LOGIN) { Task<AuthHuaweiId> authHuaweiIdTask = HuaweiIdAuthManager. parseAuthResultFromIntent(data); if (authHuaweiIdTask.isSuccessful()) { AuthHuaweiId huaweiAccount = authHuaweiIdTask.getResult(); accessToken = huaweiAccount.getAccessToken(); unionId = huaweiAccount.getUnionId(); int returnCode = init(unionId, accessToken, refreshAT); if (DriveCode.SUCCESS == returnCode) { showTips("login ok"); } else if (DriveCode.SERVICE_URL_NOT_ENABLED == returnCode) { showTips("drive is not enabled"); } else { showTips("login error"); } } else { Log.d(TAG, "onActivityResult, signIn failed: " + ((ApiException) authHuaweiIdTask.getException()).getStatusCode()); Toast.makeText(getApplicationContext(), "onActivityResult, signIn failed.", Toast.LENGTH_LONG).show(); } } } /** * Initialize Drive based on the context and HUAWEI ID information including unionId, countrycode, and accessToken. * When the current accessToken expires, register an AccessMethod and obtain a new accessToken. * * @param unionID from HwID * @param at access token * @param refreshAT a callback to refresh AT */ public int init(String unionID, String at, DriveCredential.AccessMethod refreshAT) { if (StringUtils.isNullOrEmpty(unionID) || StringUtils.isNullOrEmpty(at)) { return DriveCode.ERROR; } DriveCredential.Builder builder = new DriveCredential.Builder(unionID, refreshAT); mCredential = builder.build().setAccessToken(at); return DriveCode.SUCCESS; }

Calling the Files.create API to Create a Folder and Upload a File

API Description

API name:

public Create create(File content) throws java.io.IOException public Create create(File content, AbstractInputStreamContent mediaContent) throws java.io.IOException

API description:
This API is used to create a file and a folder. For details about the API, please refer to HUAWEI Drive Kit Development Guide.

Setting the Read and Write Permissions

Add the read and write permissions on the phone storage to app/src/main/AndroidManifest.xml.

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" tools:ignore="ProtectedPermissions" />

Add a permission request to MainActivity.java.

private static String[] PERMISSIONS_STORAGE = { Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA};

Add the code snippet for requesting the permissions to the onCreate method.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { requestPermissions(PERMISSIONS_STORAGE, 1); }

Handling a CREATE FOLDER AND UPLOAD FILE Button Event

Create a folder in the root directory of Drive, and upload the file in the designated directory to the folder. Note that the code contains global variables and functions, and you can download the sample code to view their meanings.

private void uploadFiles() { new Thread(new Runnable() { @Override public void run() { try { if (accessToken == null) { showTips("please click 'Login'."); return; } if (StringUtils.isNullOrEmpty(uploadFileName.getText().toString())) { showTips("please input upload file name above."); return; } java.io.File fileObject = new java.io.File("/sdcard/" + uploadFileName.getText()); if (!fileObject.exists()) { showTips("the input file does not exist."); return; } Drive = buildDrive(); Map<String, String> appProperties = new HashMap<>(); appProperties.put("appProperties", "property"); // Create a folder. File = new File(); file.setFileName("somepath" + System.currentTimeMillis()) .setMimeType("application/vnd.huawei-apps.folder") .setAppSettings(appProperties); if (isApplicationData.isEnabled()) { file.setParentFolder(Collections.singletonList("applicationData")); } directoryCreated = drive.files().create(file).execute(); // Upload the file. File content = new File() .setFileName(fileObject.getName()) .setMimeType(mimeType(fileObject)) .setParentFolder(Collections.singletonList(directoryCreated.getId())); drive.files() .create(content, new FileContent("image/jpeg", fileObject)) .setFields("*") .execute(); showTips("upload success"); } catch (Exception ex) { Log.d("upload error " + ex.toString()); showTips("upload error " + ex.toString()); } } }).start(); } private Drive buildDrive() { Drive service = new Drive.Builder(mCredential, this).build(); return service; } private String mimeType(java.io.File file) { if (file != null && file.exists() && file.getName().contains(".")) { String fileName = file.getName(); String suffix = fileName.substring(fileName.lastIndexOf(".")); if (MIME_TYPE_MAP.keySet().contains(suffix)) { return MIME_TYPE_MAP.get(suffix); } } return "*/*"; }

After the folder is created and the file is uploaded, the user can view the file by going to Files > HUAWEI Drive.

If applicationData is selected, the operation will be performed on the app data folder. The app data folder is invisible to users and is used to store app-specific data.

Calling the Files.list API to Query File Details by File Name

API Description

public List list() throws java.io.IOException

Handling a QUERY FILE Button Event

In the query input box, enter a file name to query file details. If applicationData is selected, the operation will be performed on the app data folder.

private void queryFiles() { new Thread(new Runnable() { @Override public void run() { try { if (accessToken == null) { showTips("please click 'Login'."); return; } String containers = ""; String queryFile = "fileName = '" + searchFileName.getText() + "' and mimeType != 'application/vnd.huawei-apps.folder'"; if (isApplicationData.isChecked()) { containers = "applicationData"; queryFile = "'applicationData' in parentFolder and ".concat(queryFile); } Drive = buildDrive(); Drive.Files.List request = drive.files().list(); FileList files; while (true) { files = request .setQueryParam(queryFile) .setPageSize(10) .setOrderBy("fileName") .setFields("category,nextCursor,files(id,fileName,size)") .setContainers(containers) .execute(); if (files == null || files.getFiles().size() > 0) { break; } if (!StringUtils.isNullOrEmpty(files.getNextCursor())) { request.setCursor(files.getNextCursor()); } else { break; } } String text = ""; if (files != null && files.getFiles().size() > 0) { fileSearched = files.getFiles().get(0); text = fileSearched.toString(); } else { text = "empty"; } final String finalText = text; MainActivity.this.runOnUiThread(new Runnable() { @Override public void run() { queryResult.setText(finalText); } }); showTips("query ok"); } catch (Exception ex) { Log.d(TAG, "query error " + ex.toString()); showTips("query error " + ex.toString()); } } }).start(); }

In this demo, the file details include the file name (fileName), file ID (id), and file size (size). If two files share the same name, only the details of one such file are shown in this demo. For more information about file details, please refer to HUAWEI Drive Kit Development Guide.

Calling the Files.Get API to Download a File

API Description

public Get get(String fileId) throws java.io.IOException

Handling a Download THE FILE Button Event

Tap the DOWNLOAD THE FILE button to download the file queried using the QUERY FILE function.

private void downloadFiles() { new Thread(new Runnable() { @Override public void run() { try { if (accessToken == null) { showTips("please click 'Login'."); return; } if (fileSearched == null) { showTips("please click 'QUERY FILE'."); return; } Drive drive = buildDrive(); File content = new File(); Drive.Files.Get request = drive.files().get(fileSearched.getId()); content.setFileName(fileSearched.getFileName()) .setId(fileSearched.getId()); MediaHttpDownloader downloader = request.getMediaHttpDownloader(); downloader.setContentRange(0, fileSearched.getSize() - 1); String filePath = "/storage/emulated/0/Huawei/Drive/DownLoad/Demo_" + fileSearched.getFileName(); request.executeContentAndDownloadTo(new FileOutputStream(new java.io.File(filePath))); showTips("download to " + filePath); } catch (Exception ex) { Log.d(TAG, "download error " + ex.toString()); showTips("download error " + ex.toString()); } } }).start(); }

After the file is successfully downloaded, you can view it in the /Huawei/Drive/DownLoad/ directory.

Calling the Comments.Create API to Comment on a File

API Description

public Create create(String fileId, Comment content) throws java.io.IOException

Handling a COMMENT THE FILE Button Event

In the comment input box, enter a comment on the file queried using the QUERY FILE function.

private void createComment() { new Thread(new Runnable() { @Override public void run() { try { if (accessToken == null) { showTips("please click 'Login'."); return; } if (fileSearched == null) { showTips("please click 'QUERY FILE'."); return; } if (StringUtils.isNullOrEmpty(commentText.getText().toString())) { showTips("please input comment above."); return; } Drive drive = buildDrive(); Comment comment = new Comment(); comment.setDescription(commentText.getText().toString()); mComment = drive.comments() .create(fileSearched.getId(), comment) .setFields("*") .execute(); if (mComment != null && mComment.getId() != null) { Log.i(TAG, "Add comment success"); showTips("Add comment success"); } else { Log.e(TAG, "Add comment failed"); showTips("Add comment failed"); } } catch (Exception ex) { Log.d(TAG, "Add comment error " + ex.toString()); showTips("Add comment error"); } } }).start(); }

After the comment is successfully added, you can view all comments on the file by using the QUERY COMMENTS function.

Calling the Comments.List API to List Comments on a File

API Description

public List list(String fileId) throws java.io.IOException

Handling a QUERY COMMENTS Button Event

List all comments on the file queried using the QUERY FILE function.

private void queryComment() { new Thread(new Runnable() { @Override public void run() { try { if (accessToken == null) { showTips("please click 'Login'."); return; } if (fileSearched == null) { showTips("please click 'QUERY FILE'."); return; } Drive drive = buildDrive(); CommentList commentList = drive.comments() .list(fileSearched.getId()) .setFields("comments(id,description,replies(description))") .execute(); final String text = response.getComments().toString(); MainActivity.this.runOnUiThread(new Runnable() { @Override public void run() { commentList.setText(text); } }); } catch (Exception ex) { Log.d(TAG, "query comments error " + ex.toString()); showTips("query comments error"); } } }).start(); }

The following figure shows an example of the listed comments. In this demo, the comment details include the comment content (description), comment ID (id), and reply content (replies/description).

Calling the Replies.Create API to Reply to a Comment

API Description

public Create create(String fileId, String commentId, Reply content) throws java.io.IOException

Handling a REPLY THE COMMENT Button Event

In the reply input box, enter a reply to the comment created using the COMMENT THE FILE function.

private void createReply() { new Thread(new Runnable() { @Override public void run() { try { if (accessToken == null) { showTips("please click 'Login'."); return; } if (fileSearched == null) { showTips("please click 'QUERY FILE'."); return; } if (mComment == null) { showTips("please click 'COMMENT THE FILE'."); return; } if (StringUtils.isNullOrEmpty(replyText.getText().toString())) { showTips("please input comment above."); return; } Drive drive = buildDrive(); Reply reply = new Reply(); reply.setDescription(replyText.getText().toString()); mReply = drive.replies() .create(fileSearched.getId(), mComment.getId(), reply) .setFields("*") .execute(); if (mReply != null && mReply.getId() != null) { Log.i(TAG, "Add reply success"); showTips("Add reply success"); } else { Log.e(TAG, "Add reply failed"); showTips("Add reply failed"); } } catch (Exception ex) { Log.d(TAG, "Add reply", ex); showTips("Add reply error"); } } }).start(); }

After the reply is successfully added, you can view all replies to the comment using the QUERY REPLIES function.

Calling the Replies.List API to List Replies to a Comment

API Description

public List list(String fileId, String commentId) throws java.io.IOException

Handling a QUERY REPLIES Button Event

List all replies to the comment created using the COMMENT THE FILE function.

private void queryReply() { new Thread(new Runnable() { @Override public void run() { try { if (accessToken == null) { showTips("please click 'Login'."); return; } if (fileSearched == null) { showTips("please click 'QUERY FILE'."); return; } if (mComment == null) { showTips("please click 'COMMENT THE FILE'."); return; } Drive drive = buildDrive(); ReplyList response = drive.replies() .list(fileSearched.getId(), mComment.getId()) .setFields("replies(id,description)") .execute(); final String text = response.getReplies().toString(); MainActivity.this.runOnUiThread(new Runnable() { @Override public void run() { replyList.setText(text); } }); } catch (Exception ex) { Log.d(TAG, "query Reply error " + ex.toString()); showTips("query reply error"); } } }).start(); }

The following figure shows an example of listed replies. In this demo, the reply details include the reply content (description) and reply ID (id).

Calling the HistoryVersion.List API to List Historical Versions of a File

API Description

public List list(String fileId) throws java.io.IOException

Handling a LIST HISTORYVERSION Button Event

List all historical versions of the file queried using the QUERY FILE function.

private void queryHistoryVersion() { new Thread(new Runnable() { @Override public void run() { try { if (accessToken == null) { showTips("please click 'Login'."); return; } if (fileSearched == null) { showTips("please click 'QUERY FILE'."); return; } Drive drive = buildDrive(); HistoryVersionList response = drive.historyVersions() .list(fileSearched.getId()) .setFields("historyVersions(id,sha256) ") .execute(); final String text = response.getHistoryVersions().toString(); MainActivity.this.runOnUiThread(new Runnable() { @Override public void run() { historyVersionList.setText(text); } }); } catch (Exception ex) { Log.d(TAG, "query historyVersion error " + ex.toString()); showTips("query historyVersion error"); } } }).start(); }

The following figure shows an example of listed historical versions. In this demo, the historical version details include the version ID (id) and version SHA256 (sha256).

Follow-up

In your Android Studio, click Run. Select your mobile phone as the target, and click OK to run the Drive demo on the mobile phone. The following page will display.

Downloading the Drive Sample Code

You can click the following button to download the Drive Kit sample code used in this codelab:

Download

Well done. You have successfully developed your first app using Drive Kit!

In this codelab, you have learned:

You have now learned all of the key operations required to create an app that uses Drive Kit.

What Else You Can Do

You can read code snippets in the following file:
com/huawei/www/driveapplication/MainActivity.java

For more information, please click the following link:

Documentation

Code copied