首页 > 其他分享 >【HMS Core】构建SplitBill应用集成多个HMS Core服务,助力您更好的了解华为生态组成

【HMS Core】构建SplitBill应用集成多个HMS Core服务,助力您更好的了解华为生态组成

时间:2022-11-23 09:44:52浏览次数:68  
标签:Core Log void HMS TAG SplitBill new import public

​一、介绍

Duration: 3:00

总览

通过构建本次的SplitBill应用,您可以更好地了解华为生态的组成部分,包括认证服务、云存储和云数据库等Serverless服务。此外您还可以了解如何使用近距离数据通信服务的Nearby Connection功能分享文件。无需使用现金,SplitBill应用能够实现用户与其他任意用户共同支付账单。

您将建立什么

在本次的Codelab中,您将建立一款SplitBill应用,并使用到华为认证服务、Network Kit、近距离数据通信服务、云数据库和云存储的接口。该应用为用户提供端到端的群收款服务。使用该应用,多位用户可以组成一个群,共同完成账单支付。

您将学到什么

  • 使用认证服务登录应用(华为账号和手机号认证方式)

  • 创建群。

  • 添加成员到群。

  • 添加账单。

  • 上传用户头像至云存储和在云数据库中更新头像。

  • 使用近距离通信服务分享账单文件。

二、您需要什么

Duration: 2:00

开发环境

  • 一台装有Windows10操作系统的台式或笔记本电脑。

  • 搭载HMC Core(APK)5.0.0.300或以上版本的华为手机。

  • 通过验证华为账号

设备要求

一部用于测试的安卓手机或模拟器。

三、集成准备

Duration: 10:00

在集成SDK之前,您需要完成以下准备:

  • 在AppGallery Connect上创建应用。

  • 创建一个安卓项目。

  • 生成签名证书。

  • 生成签名证书指纹。

  • 配置签名证书指纹。

  • 添加应用包名,保存配置文件。

  • 在项目级build.gradle文件中添加AppGallery Connect插件和Maven仓。

  • 在Android Studio中配置签名证书。

详情请见HUWEI HMS Core集成准备

说明:在上述准备工作前您需要注册成为一名开发者。

四、开通服务

Duration: 4:00

首先,您需要在AppGallery Connect上启用HMS Core的相关服务。启用前,请完成以下准备工作:

1、登录AppGallery Connect,点击“项目设置”中“API管理”页签,开通如下服务的API权限。

  • 认证服务(华为账号认证方式)

  • 云数据库

  • 云存储

  • 近距离通信服务

  • Network Kit

cke_22898.png

cke_24882.png

cke_27208.png

cke_29271.png

说明:以上API权限默认已开通。如未开通,请手动开通。

2、在弹出的页面设置数据处理位置。

cke_37905.png

五、集成SDK

Duration: 4:00

您需要将云数据库SDK集成到您的Android Studio项目中。

1、登录AppGallery Connect,点击“我的项目”。

2、点击您的项目,在顶部的应用下拉列表中选择应用。

3、点击“项目设置”>“常规”。在“应用”区域,下载agconnect-services.json文件。

cke_64778.png

 

4、将agconnect-services.json文件复制到您的项目中。

cke_71966.png

5、在Android Studio中,打开项目级build.gradle文件,前往allprojects > repositories,在buildscript的repositories部分配置Maven仓地址。

cke_80468.png

cke_84522.png

6、在buildscript的dependencies部分配置AppGallery Connect插件。

buildscript { 
    dependencies { 
        classpath 'com.huawei.agconnect:agcp:<version>'
    } 
}

7、在应用级build.gradle文件中添加AppGallery Connect插件。

apply plugin: 'com.huawei.agconnect'

8、(可选)在Application类中的onCreate方法里添加初始化代码。

if (AGConnectInstance.getInstance() == null) {
AGConnectInstance.initialize(getApplicationContext()); 
}

9、在应用级build.gradle文件里的dependencies部分添加所需依赖路径。

implementation 'com.huawei.agconnect:agconnect-auth:<version>'
implementation 'com.huawei.hms:hwid:<version>'
implementation 'com.huawei.hms:nearby: <version>'
implementation"com.huawei.agconnect:agconnect-storage:<version>"
 implementation'com.huawei.agconnect:agconnect-cloud-database:<version>'

六、设计UI

Duration: 5:00

创建以下界面:登录、建群、群列表、添加账单、账单和收支标签页、账单详情、账单分享详情和收到的账单文件列表。

用户登录界面

cke_136790.png

群列表和建群界面

cke_147222.pngcke_150144.pngcke_154068.pngcke_159027.png

七、前提准备

Duration: 5:00

认证服务

认证服务SDK能够让您快速便捷地在您的应用上实现用户注册和登录功能。

  1. 登录AppGallery Connect,点击“我的项目”。

  2. 点击您的项目。

  3. 选择“构建”,单击“认证服务”。若您首次使用认证服务,点击“立即开通”。

  4. 单击“认证方式”,在“操作”栏中启用华为账号认证方式。

cke_185653.png

Cloud DB

使用云数据库服务,您需要启用云数据库,创建存储区和云数据库对象所需字段。

1、登录AppGallery Connect,点击“我的项目”。

2、点击您的项目。

3、选择“构建”,点击“云数据库”。若您首次使用云数据库,点击“立即开通”。

4、在弹出页面设置数据处理位置。

5、单击“新增”,进入创建对象类型页面。

cke_218809.png

6、设置对象类型,单击“下一步”。

7、单击“+新增字段”添加字段,单击“下一步”。

8、添加所需索引。

9、设置各角色权限。

cke_248030.png

10、单击“确定”。返回对象类型列表,查看已创建的对象类型。

11、单击“导出”。

cke_282257.png

12、选择文件格式,此处选择文件类型为Java,文件格式为Android。输入包名,点击“确定”。对象类型文件将被作为zip文件下载

13、提取zip中的文件至项目的model包里。

1)点击“存储区”页签。

2)单击“新增”,进入创建存储区页面。

cke_345998.png

云存储

使用云存储服务,您需要启用云存储,并在开发前完成下述操作。

1、启用云存储后,创建存储实例,单击“下一步”。

2、创建安全策略,控制是否允许未经认证的用户访问存储。单击“完成”。

cke_365965.png

3、完成上述操作后,您即可使用云存储服务。

八、实现功能

Duration: 15:00

完成准备工作后,集成认证服务、云数据库、云存储、Network Kit和近距离通信服务到您的应用中。

在已设计好的登录页面添加如下代码,实现华为账号登录按钮。

activityAuthBinding.tvGetcode.setOnClickListener(this);
activityAuthBinding.btnHuaweiId.setOnClickListener(this);
HuaweiIdAuthParamsHelper huaweiIdAuthParamsHelper = new HuaweiIdAuthParamsHelper(HuaweiIdAuthParams.DEFAULT_AUTH_REQUEST_PARAM);
scopeList = new ArrayList<>();
scopeList.add(new Scope(HwIDConstant.SCOPE.ACCOUNT_BASEPROFILE));
scopeList.add(new Scope(HwIDConstant.SCOPE.SCOPE_ACCOUNT_EMAIL));
scopeList.add(new Scope(HwIDConstant.SCOPE.SCOPE_MOBILE_NUMBER));
scopeList.add(new Scope(HwIDConstant.SCOPE.SCOPE_ACCOUNT_PROFILE));
huaweiIdAuthParamsHelper.setScopeList(scopeList);
HuaweiIdAuthParams authParams = huaweiIdAuthParamsHelper.setAccessToken().setMobileNumber().createParams();
 service = HuaweiIdAuthManager.getService(this, authParams);

 Button Click:
loginViewModel.signInWithHuaweiId(AuthActivity.this, service).observe(AuthActivity.this, new Observer<SignInResult>() {
     @Override
     public void onChanged(SignInResult user) {
         activityAuthBinding.authProgressBar.setVisibility(View.VISIBLE);
         progress();
         loginSuccess (user);
     }
 });

实现OnActivityResult。

huaweiSignIn.launch(service.getSignInIntent());
ActivityResultLauncher<Intent> huaweiSignIn = AuthActivity.authActivity.registerForActivityResult(
         new ActivityResultContracts.StartActivityForResult(),
         new ActivityResultCallback<ActivityResult>() {
             @Override
             public void onActivityResult(ActivityResult result) {

                 if (result.getResultCode() == Activity.RESULT_OK) {

                     Task<AuthAccount> authAccountTask = AccountAuthManager.parseAuthResultFromIntent(result.getData());
                     if (authAccountTask.isSuccessful()) {
                         AuthAccount authAccount = authAccountTask.getResult();

                         AGConnectAuthCredential credential = HwIdAuthProvider.credentialWithToken(authAccount.getAccessToken());
                         AGConnectAuth.getInstance().signIn(credential).addOnSuccessListener(new OnSuccessListener<SignInResult>() {
                             @Override
                             public void onSuccess(SignInResult signInResult) {
                                 // onSuccess
                                 Common.showToast("log in", AuthActivity.authActivity);
                                 authenticatedUserMutableLiveData.setValue(signInResult);

                             }
                         })
                                 .addOnFailureListener(new OnFailureListener() {
                                     @Override
                                     public void onFailure(Exception e) {
                                         Common.showToast("fail", AuthActivity.authActivity);
                                     }
                                 });
                     }
                 }
             }
         });

创建wrapper类,用于初始化云数据库存储区,插入新用户和验证已知用户等数据库操作。

public class CloudDBZoneWrapper {      private static final String TAG = "CloudDBZoneWrapper";     private static final String DB_NAME = "SplitBillSampleApp";     private AGConnectCloudDB mCloudDB;     private CloudDBZone mCloudDBZone;     private CloudDBZoneConfig mConfig;  /**
  SplitBillApplication
* Get instance of Cloud DB zone wrapper to initiate cloud DB  *  * @return mCloudDBZoneWrapper  */ public CloudDBZoneWrapper getCloudDBZoneWrapper() {     if (mCloudDBZoneWrapper != null) {         return mCloudDBZoneWrapper;     }     mCloudDBZoneWrapper = new CloudDBZoneWrapper();     return mCloudDBZoneWrapper; }
 
/**  * Get CloudDB task to open AGConnectCloudDB  */ public Task<CloudDBZone> openCloudDBZoneV2() {     mConfig = new CloudDBZoneConfig(DB_NAME,             CloudDBZoneConfig.CloudDBZoneSyncProperty.CLOUDDBZONE_CLOUD_CACHE,             CloudDBZoneConfig.CloudDBZoneAccessProperty.CLOUDDBZONE_PUBLIC);     mConfig.setPersistenceEnabled(true);     Task<CloudDBZone> openDBZoneTask = mCloudDB.openCloudDBZone2(mConfig, true);     return openDBZoneTask; }
/**
  * 调用AGConnectCloudDB.closeCloudDBZone
  */
public void closeCloudDBZone() {
     try {
         mRegister.remove();
         mCloudDB.closeCloudDBZone(mCloudDBZone);
     } catch (AGConnectCloudDBException e) {
         Log.w(TAG, "CloudDBZone: " + e.getMessage());
     }
}
 
/**
  * 云数据库中插入好友数据
  */
public MutableLiveData<Boolean> upsertExpenseData(Friends friends) {
     if (mCloudDBZone == null) {
         Log.w(TAG, "CloudDBZone is null, try re-open it");
     }

     Task<Integer> upsertTask = mCloudDBZone.executeUpsert(friends);
     upsertTask.addOnSuccessListener(new OnSuccessListener<Integer>() {
         @Override
         public void onSuccess(Integer cloudDBZoneResult) {
             friendsUpdateSuccess.postValue(true);
         }
     }).addOnFailureListener(new OnFailureListener() {
         @Override
         public void onFailure(Exception e) {
             friendsUpdateSuccess.postValue(false);
         }
     });
     return friendsUpdateSuccess;
 }
/**
  * 云数据库中获取好友列表
  */
 
public MutableLiveData<Integer> getFriendsIdLiveData() {
     CloudDBZoneQuery<Friends> snapshotQuery = CloudDBZoneQuery.where(Friends.class);
     Task<Long> countQueryTask = mCloudDBZone.executeCountQuery(snapshotQuery, FriendsEditFields.CONTACT_ID,
             CloudDBZoneQuery.CloudDBZoneQueryPolicy.POLICY_QUERY_FROM_CLOUD_ONLY);
     countQueryTask.addOnSuccessListener(new OnSuccessListener<Long>() {
         @Override
         public void onSuccess(Long aLong) {
             Log.i(TAG, "The total number of groups is " + aLong);
             friendsIdLiveData.postValue((int) (aLong + 1));
         }
     }).addOnFailureListener(new OnFailureListener() {
         @Override
         public void onFailure(Exception e) {
             Log.w(TAG, "Count query is failed: " + Log.getStackTraceString(e));
         }
     });

     return friendsIdLiveData;
 }
/**
  * 云数据库中获取好友列表
 
  * 从数据库中添加,获取群或账单数据使用相似方法。
*/
private void insertGroupDataInDB(Group group){
     groupViewModel.upsertGroupData(group).observe(getActivity(), new Observer<Boolean>() {
         @Override
         public void onChanged(Boolean aBoolean) {
             if (aBoolean.equals(true)) {
                 progressStats = true;
                 Toast.makeText(getContext(), getString(R.string.add_group_success) + " " + group.getName(), Toast.LENGTH_LONG).show();
                 Navigation.findNavController(fragmentCreateGroupBinding.getRoot()).navigate(R.id.navigation_activity);
             } else {
                 Toast.makeText(getContext(), getString(R.string.add_group_failed), Toast.LENGTH_LONG).show();
                 progressStats = false;
             }
         }
     });
 }
 
 
 
   
添加账单数据:
private void addExpenseData() {
     Expense expense = new Expense();
     String strExpenseName = expenseName.getText().toString();
     String strPaidBy = spinner.getSelectedItem().toString();
     String strExpenseAmount = expenseDesc.getText().toString();
     expense.setId(0);
     expense.setName(strExpenseName);

     expense.setAmount(Float.parseFloat((strExpenseAmount) + ".00"));
     expense.setPaid_user_id(0);
     expense.setStatus(1);
     expenseViewModel.upsertExpenseData(expense).observe(getActivity(), new Observer<Boolean>() {
         @Override
         public void onChanged(Boolean aBoolean) {
             if (aBoolean.equals(true)) {
                 Toast.makeText(getContext(), getString(R.string.add_expense_success) + " " + strExpenseName, Toast.LENGTH_LONG).show();
                 //TODO : back key
                 
             } else {
                 Toast.makeText(getContext(), getString(R.string.add_expense_failed), Toast.LENGTH_LONG).show();
             }
         }
     });
 }

数据插入完成后,接着使用近距离通信服务提供的类。

NearbyAgent:
/*
  * 华为技术有限公司版权所有 保留一切权利,
     授权于Apache License 2.0版本(以下简称“许可证”)。
    使用此许可证时,须遵循其规定。
     您可以通过以下途径获取许可证的副本:
      http://www.apache.org/licenses/LICENSE-2.0
    除非得到适用法律或书面同意,
    许可证许可范围内所提供的软件均按“现状”提供,
    而不做任何明示或暗示的保证。
    关于许可证中特定语言的权限和限制,
    请参见许可证。
  */

package com.huawei.codelabs.splitbill.ui.main.helper;

import android.Manifest;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.graphics.pdf.PdfDocument;
import android.net.Uri;
import android.os.Environment;
import android.util.Log;
import android.view.View;


import androidx.core.app.ActivityCompat;
import androidx.documentfile.provider.DocumentFile;
import androidx.fragment.app.FragmentActivity;
import androidx.recyclerview.widget.LinearLayoutManager;

import com.huawei.codelabs.splitbill.R;
import com.huawei.codelabs.splitbill.databinding.FragmentAccountBinding;
import com.huawei.codelabs.splitbill.databinding.FragmentFileDetailsBinding;
import com.huawei.codelabs.splitbill.databinding.FragmentSendExpenseDetailsBinding;
import com.huawei.codelabs.splitbill.ui.main.activities.MainActivity;
import com.huawei.codelabs.splitbill.ui.main.adapter.DeviceAdapter;
import com.huawei.codelabs.splitbill.ui.main.adapter.FilesAdapter;
import com.huawei.codelabs.splitbill.ui.main.adapter.FriendsListAdapter;
import com.huawei.codelabs.splitbill.ui.main.models.Device;
import com.huawei.codelabs.splitbill.ui.main.models.Files;
import com.huawei.hms.hmsscankit.ScanUtil;
import com.huawei.hms.hmsscankit.WriterException;
import com.huawei.hms.ml.scan.HmsBuildBitmapOption;
import com.huawei.hms.ml.scan.HmsScan;
import com.huawei.hms.ml.scan.HmsScanAnalyzerOptions;
import com.huawei.hms.nearby.Nearby;
import com.huawei.hms.nearby.StatusCode;
import com.huawei.hms.nearby.discovery.BroadcastOption;
import com.huawei.hms.nearby.discovery.ConnectCallback;
import com.huawei.hms.nearby.discovery.ConnectInfo;
import com.huawei.hms.nearby.discovery.ConnectResult;
import com.huawei.hms.nearby.discovery.DiscoveryEngine;
import com.huawei.hms.nearby.discovery.Policy;
import com.huawei.hms.nearby.discovery.ScanEndpointCallback;
import com.huawei.hms.nearby.discovery.ScanEndpointInfo;
import com.huawei.hms.nearby.discovery.ScanOption;
import com.huawei.hms.nearby.transfer.Data;
import com.huawei.hms.nearby.transfer.DataCallback;
import com.huawei.hms.nearby.transfer.TransferEngine;
import com.huawei.hms.nearby.transfer.TransferStateUpdate;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

import static java.nio.charset.StandardCharsets.UTF_8;

public class NearbyAgent {
     public static final int REQUEST_CODE_SCAN_ONE = 0X01;
     private static final String[] REQUIRED_PERMISSIONS =
             new String[]{Manifest.permission.ACCESS_COARSE_LOCATION,
                     Manifest.permission.ACCESS_FINE_LOCATION,
                     Manifest.permission.ACCESS_WIFI_STATE,
                     Manifest.permission.CHANGE_WIFI_STATE,
                     Manifest.permission.BLUETOOTH,
                     Manifest.permission.BLUETOOTH_ADMIN,
                     Manifest.permission.READ_EXTERNAL_STORAGE,
                     Manifest.permission.WRITE_EXTERNAL_STORAGE,
                     Manifest.permission.CAMERA};
     private static final int REQUEST_CODE_REQUIRED_PERMISSIONS = 1;
     private final String TAG = "Nearby_Agent";
     private final String mFileServiceId = "NearbyAgentFileService";
     private final String mEndpointName = android.os.Build.DEVICE;
     int lineYAxis = 350;
     FragmentAccountBinding fragmentAccountBinding;
     FragmentSendExpenseDetailsBinding fragmentSendExpenseDetailsBinding;
     FragmentFileDetailsBinding fragmentFileDetailsBinding;
     ArrayList<Files> filesArrayList;
     FilesAdapter groupAdapter;
     private MainActivity mContext = null;
     private TransferEngine mTransferEngine = null;
     private DiscoveryEngine mDiscoveryEngine = null;
     private List<File> mFiles = new ArrayList<>();
     private String mRemoteEndpointId;
     private String mRemoteEndpointName;
     private String mScanInfo;
     private final ScanEndpointCallback mDiscCb =
             new ScanEndpointCallback() {
                 @Override
                 public void onFound(String endpointId, ScanEndpointInfo discoveryEndpointInfo) {
                     if (discoveryEndpointInfo.getName().equals(mScanInfo)) {

                         Log.d(TAG, "Found endpoint:" + discoveryEndpointInfo.getName() + ". Connecting.");
                         mDiscoveryEngine.requestConnect(mEndpointName, endpointId, mConnCbRcver);
                     }
                 }

                 @Override
                 public void onLost(String endpointId) {
                     Log.d(TAG, "Lost endpoint.");
                 }
             };
     private String mRcvedFilename = null;
     private Bitmap mResultImage;
     private String mFileName;
     private long mStartTime = 0;
     private float mSpeed = 60;
     private String mSpeedStr = "60";
     private boolean isTransfer = false;
     private final DataCallback mDataCbSender =
             new DataCallback() {
                 @Override
                 public void onReceived(String endpointId, Data data) {
                     if (data.getType() == Data.Type.BYTES) {
                         String msg = new String(data.asBytes(), UTF_8);
                         if (msg.equals("Receive Success")) {
                             Log.d(TAG, "Received ACK. Send next.");
                             sendOneFile();
                         }
                     }
                 }

                 @Override
                 public void onTransferUpdate(String string, TransferStateUpdate update) {
                     if (update.getStatus() == TransferStateUpdate.Status.TRANSFER_STATE_SUCCESS) {
                     } else if (update.getStatus() == TransferStateUpdate.Status.TRANSFER_STATE_IN_PROGRESS) {
                         showProgressSpeedSender(update);
                     } else if (update.getStatus() == TransferStateUpdate.Status.TRANSFER_STATE_FAILURE) {
                         Log.d(TAG, "Transfer failed.");
                     } else {
                         Log.d(TAG, "Transfer cancelled.");
                     }
                 }
             };
     private final ConnectCallback mConnCbRcver =
             new ConnectCallback() {
                 @Override
                 public void onEstablish(String endpointId, ConnectInfo connectionInfo) {
                     Log.d(TAG, "Accept connection.");
                     mRemoteEndpointName = connectionInfo.getEndpointName();
                     mRemoteEndpointId = endpointId;
                     mDiscoveryEngine.acceptConnect(endpointId, mDataCbRcver);
                 }

                 @Override
                 public void onResult(String endpointId, ConnectResult result) {
                     if (result.getStatus().getStatusCode() == StatusCode.STATUS_SUCCESS) {
                         Log.d(TAG, "Connection Established. Stop Discovery.");
                         mDiscoveryEngine.stopBroadcasting();
                         mDiscoveryEngine.stopScan();
                         fragmentFileDetailsBinding.tvMainDesc.setText("Connected.");
                     }
                 }

                 @Override
                 public void onDisconnected(String endpointId) {
                     Log.d(TAG, "Disconnected.");
                     if (isTransfer == true) {
                         fragmentSendExpenseDetailsBinding.tvMainDesc.setVisibility(View.GONE);
                         fragmentSendExpenseDetailsBinding.tvMainDesc.setText("Connection lost.");
                     }
                 }
             };
     private Data incomingFile = null;
     private final DataCallback mDataCbRcver =
             new DataCallback() {
                 @Override
                 public void onReceived(String endpointId, Data data) {
                     if (data.getType() == Data.Type.BYTES) {
                         String msg = new String(data.asBytes(), UTF_8);
                         mRcvedFilename = msg;
                         Log.d(TAG, "received filename: " + mRcvedFilename);
                         isTransfer = true;
                         fragmentFileDetailsBinding.tvMainDesc.setText(new StringBuilder("Receiving file ").append(mRcvedFilename).append(" from ").append(mRemoteEndpointName + ".").toString());
                         fragmentFileDetailsBinding.pbMainDownload.setVisibility(View.VISIBLE);
                     } else if (data.getType() == Data.Type.FILE) {
                         incomingFile = data;
                     } else {
                         Log.d(TAG, "received stream. ");
                     }
                 }

                 public  File getLastModified(String directoryFilePath)
                 {
                     File directory = new File(directoryFilePath);
                     File[] files = directory.listFiles(File::isFile);
                     long lastModifiedTime = Long.MIN_VALUE;
                     File chosenFile = null;

                     if (files != null)
                     {
                         for (File file : files)
                         {
                             if (file.lastModified() > lastModifiedTime)
                             {
                                 chosenFile = file;
                                 lastModifiedTime = file.lastModified();
                             }
                         }
                     }

                     return chosenFile;
                 }
                 @Override
                 public void onTransferUpdate(String string, TransferStateUpdate update) {
                     if (update.getStatus() == TransferStateUpdate.Status.TRANSFER_STATE_SUCCESS) {
                     } else if (update.getStatus() == TransferStateUpdate.Status.TRANSFER_STATE_IN_PROGRESS) {
                         showProgressSpeedReceiver(update);
                         if (update.getBytesTransferred() == update.getTotalBytes()) {
                             Log.d(TAG, "File transfer done. Rename File.");
                             renameFile();
                             Log.d(TAG, "Send Ack.");
                             fragmentFileDetailsBinding.tvMainDesc.setText(new StringBuilder("Transfer success. Speed: ").append(mSpeedStr).append("MB/s. \nView the File at /Sdcard/Download/Nearby"));
                             mTransferEngine.sendData(mRemoteEndpointId, Data.fromBytes("Receive Success".getBytes(StandardCharsets.UTF_8)));
                             isTransfer = false;
                             Files files = new Files();
                             File file=  getLastModified(Environment.getExternalStorageDirectory().getPath() + Constants.DOWNLOAD_PATH);
                             files.setFileName(file.getName());
                             files.setFilePath(new File(file.getAbsolutePath()));
                             filesArrayList.add(files);
                             groupAdapter.notifyDataSetChanged();
                         }
                     } else if (update.getStatus() == TransferStateUpdate.Status.TRANSFER_STATE_FAILURE) {
                         Log.d(TAG, "Transfer failed.");
                     } else {
                         Log.d(TAG, "Transfer cancelled.");
                     }
                 }
             };
     private ArrayList<Device> deviceList;
     private final ConnectCallback mConnCbSender =
             new ConnectCallback() {
                 @Override
                 public void onEstablish(String endpointId, ConnectInfo connectionInfo) {
                     Log.d(TAG, "Accept connection.");
                     mDiscoveryEngine.acceptConnect(endpointId, mDataCbSender);
                     fragmentSendExpenseDetailsBinding.rcDevice.setHasFixedSize(true);
                     fragmentSendExpenseDetailsBinding.rcDevice.setLayoutManager(new LinearLayoutManager(mContext));
                     Device device = new Device();
                     device.setDeviceName(connectionInfo.getEndpointName());
                     deviceList.add(device);
                     DeviceAdapter deviceAdapter = new DeviceAdapter(deviceList);
                     fragmentSendExpenseDetailsBinding.rcDevice.setAdapter(deviceAdapter);
                     deviceAdapter.notifyDataSetChanged();
                     mRemoteEndpointName = connectionInfo.getEndpointName();
                     mRemoteEndpointId = endpointId;
                 }

                 @Override
                 public void onResult(String endpointId, ConnectResult result) {
                     if (result.getStatus().getStatusCode() == StatusCode.STATUS_SUCCESS) {
                         Log.d(TAG, "Connection Established. Stop discovery. Start to send file.");
                         mDiscoveryEngine.stopScan();
                         mDiscoveryEngine.stopBroadcasting();
                         sendOneFile();
                         fragmentSendExpenseDetailsBinding.barcodeImage.setVisibility(View.GONE);
                         fragmentSendExpenseDetailsBinding.tvMainDesc.setText(new StringBuilder("MB/s. \nView the File at /Sdcard/Download/Nearby").append(mFileName).append(" to ").append(mRemoteEndpointName).append("."));
                         fragmentSendExpenseDetailsBinding.pbMainDownload.setVisibility(View.GONE);
                     }
                 }

                 @Override
                 public void onDisconnected(String endpointId) {
                     Log.d(TAG, "Disconnected.");
                     if (isTransfer == true) {
                         fragmentSendExpenseDetailsBinding.pbMainDownload.setVisibility(View.GONE);
                         fragmentSendExpenseDetailsBinding.tvMainDesc.setText("Connection lost.");
                     }
                 }
             };

     public NearbyAgent(MainActivity context) {
         mContext = context;
         mDiscoveryEngine = Nearby.getDiscoveryEngine(context);
         deviceList = new ArrayList<>();
         mTransferEngine = Nearby.getTransferEngine(context);
         if (context instanceof MainActivity) {
             ActivityCompat.requestPermissions(context, REQUIRED_PERMISSIONS, REQUEST_CODE_REQUIRED_PERMISSIONS);
         }
     }

     public NearbyAgent(MainActivity context, FragmentAccountBinding fragmentAccountBinding) {
         this.fragmentAccountBinding = fragmentAccountBinding;
         this.mContext = context;
         mDiscoveryEngine = Nearby.getDiscoveryEngine(context);
         mTransferEngine = Nearby.getTransferEngine(context);
         if (context instanceof MainActivity) {
             ActivityCompat.requestPermissions(context, REQUIRED_PERMISSIONS, REQUEST_CODE_REQUIRED_PERMISSIONS);
         }


     }

     public static String getFileRealNameFromUri(Context context, Uri fileUri) {
         if (context == null || fileUri == null) {
             return Constants.UnknownFile;
         }
         DocumentFile documentFile = DocumentFile.fromSingleUri(context, fileUri);
         if (documentFile == null) {
             return Constants.UnknownFile;
         }
         return documentFile.getName();
     }

     private void showProgressSpeedSender(TransferStateUpdate update) {
         long transferredBytes = update.getBytesTransferred();
         long totalBytes = update.getTotalBytes();
         long curTime = System.currentTimeMillis();
         Log.d(TAG, "Transfer in progress. Transferred Bytes: "
                 + transferredBytes + " Total Bytes: " + totalBytes);
         fragmentSendExpenseDetailsBinding.pbMainDownload.setProgress((int) (transferredBytes * 100 / totalBytes));
         if (mStartTime == 0) {
             mStartTime = curTime;
         }
         if (curTime != mStartTime) {
             mSpeed = ((float) transferredBytes) / ((float) (curTime - mStartTime)) / 1000;
             java.text.DecimalFormat myformat = new java.text.DecimalFormat("0.00");
             mSpeedStr = myformat.format(mSpeed);
             fragmentSendExpenseDetailsBinding.tvMainDesc.setText(new StringBuilder("Transfer in Progress. Speed: ").append(mSpeedStr).append("MB/s."));
         }
         if (transferredBytes == totalBytes) {
             mStartTime = 0;
         }
     }

     public void loadScanCode(Bitmap mResultImage) {
         
         fragmentSendExpenseDetailsBinding.barcodeImage.setVisibility(View.VISIBLE);
         fragmentSendExpenseDetailsBinding.barcodeImage.setImageBitmap(mResultImage);
     }

     public File createPdf(List<FriendsListAdapter.FriendsUI> friendsUIList, Bitmap scaledImageBitmap, FragmentActivity activity) {
         //创建一个新的document。
         PdfDocument document = new PdfDocument();
         //创建页面描述。
         PdfDocument.PageInfo pageInfo = new PdfDocument.PageInfo.Builder(Constants.PAGEWIDTH, Constants.PAGEHEIGHT, 1).create();
         //开启一个页面。
         PdfDocument.Page page = document.startPage(pageInfo);
         Canvas canvas = page.getCanvas();
         Paint paint = new Paint();
         canvas.drawBitmap(scaledImageBitmap, 0, 0, paint);
         paint.setTextAlign(Paint.Align.CENTER);
         paint.setTextSize(50);
         paint.setColor(activity.getResources().getColor(android.R.color.black));
         paint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.NORMAL));
         canvas.drawText("Invoice" + System.currentTimeMillis(), Constants.PAGEWIDTH / 2, 260, paint);
         paint.setStrokeWidth(2f);
         
         canvas.drawLine(Constants.PAGEWIDTH / 2, 300, 550, 300, paint);
         canvas.drawText("Amount" + "     " + "Participants", Constants.PAGEWIDTH / 2, 400, paint);
         lineYAxis = 450;
         for (FriendsListAdapter.FriendsUI friendsUI : friendsUIList) {
             canvas.drawText(friendsUI.getFriendsName() + "     " + friendsUI.getAmount() + "", Constants.PAGEWIDTH / 2, Constants.LINEYAXIS + 50, paint);
             lineYAxis = lineYAxis + 50;
         }
         
         document.finishPage(page);
         
         pageInfo = new PdfDocument.PageInfo.Builder(Constants.PAGEWIDTH, Constants.PAGEHEIGHT, 2).create();
         page = document.startPage(pageInfo);
         document.finishPage(page);
         //写入document内容。
         String directory_path = Environment.getExternalStorageDirectory().getPath() + Constants.CREATEINVOICE;
         File file = new File(directory_path);
         if (!file.exists()) {
             file.mkdirs();
         }
         String targetPdf = new StringBuilder().append(directory_path).append("invoice").append(System.currentTimeMillis()).append(".pdf").toString();
         File filePath = new File(targetPdf);
         try {
             document.writeTo(new FileOutputStream(filePath));

         } catch (IOException e) {
             Log.e("main", "error " + e.toString());

         }
         //关闭document。
         document.close();
         return filePath;
     }

     public void sendFile(File file, FragmentSendExpenseDetailsBinding fragmentSendExpenseDetailsBinding) {
         this.fragmentSendExpenseDetailsBinding = fragmentSendExpenseDetailsBinding;

         init();
         mFiles.add(file);
         sendFilesInner();
     }

     public void sendFiles(List<File> files) {
         init();
         mFiles = files;
         sendFilesInner();
     }

     public void sendFolder(File folder) {
         init();
         File[] subFile = folder.listFiles();
         for (int i = 0; i < subFile.length; i++) {
             if (!subFile[i].isDirectory()) {
                 mFiles.add(subFile[i]);
                 Log.d(TAG, "Travel folder: " + subFile[i].getName());
             }
         }
         sendFilesInner();
     }

     private void sendFilesInner() {

         /* 生成bitmap */
         try {
             //生成barcode。
             HmsBuildBitmapOption options = new HmsBuildBitmapOption.Creator().setBitmapMargin(1).setBitmapColor(Color.BLACK).setBitmapBackgroundColor(Color.WHITE).create();
             mResultImage = ScanUtil.buildBitmap(mEndpointName, HmsScan.QRCODE_SCAN_TYPE, Constants.BARCODE_SIZE, Constants.BARCODE_SIZE, options);
             loadScanCode(mResultImage);
         } catch (WriterException e) {
             Log.e(TAG, e.toString());
         }
         /* 开始广播 */
         BroadcastOption.Builder advBuilder = new BroadcastOption.Builder();
         advBuilder.setPolicy(Policy.POLICY_P2P);
         mDiscoveryEngine.startBroadcasting(mEndpointName, mFileServiceId, mConnCbSender, advBuilder.build());
         Log.d(TAG, "Start Broadcasting.");

     }

     public void receiveFile(FragmentFileDetailsBinding fragmentFileDetailsBinding, ArrayList<Files> filesArrayList, FilesAdapter groupAdapter) {
         /* 扫描bitmap */
         this.fragmentFileDetailsBinding = fragmentFileDetailsBinding;
         this.filesArrayList=filesArrayList;
         this.groupAdapter=groupAdapter;
         Log.d("TAG", "start");
         init();
         HmsScanAnalyzerOptions options = new HmsScanAnalyzerOptions.Creator().setHmsScanTypes(HmsScan.QRCODE_SCAN_TYPE, HmsScan.DATAMATRIX_SCAN_TYPE).create();
         ScanUtil.startScan(mContext, REQUEST_CODE_SCAN_ONE, options);
         Log.d("TAG", "Sent");
     }

     public void onScanResult(Intent data) {
         if (data == null) {
             Log.d("TAG", "fail");
             fragmentFileDetailsBinding.tvMainDesc.setText("Scan Failed.");
             return;
         }
         /* 保存设备名称*/
         HmsScan obj = data.getParcelableExtra(ScanUtil.RESULT);
         mScanInfo = obj.getOriginalValue();
         /* 开始扫描*/
         ScanOption.Builder scanBuilder = new ScanOption.Builder();
         scanBuilder.setPolicy(Policy.POLICY_P2P);
         mDiscoveryEngine.startScan(mFileServiceId, mDiscCb, scanBuilder.build());
         Log.d(TAG, "Start Scan.");
         fragmentFileDetailsBinding.tvMainDesc.setText(new StringBuilder().append("Connecting to ").append(mScanInfo).append("..."));
     }

     private void sendOneFile() {
         Data filenameMsg = null;
         Data filePayload = null;
         isTransfer = true;
         Log.d(TAG, "Left " + mFiles.size() + " Files to send.");
         if (mFiles.isEmpty()) {
             Log.d(TAG, "All Files Done. Disconnect");
             fragmentSendExpenseDetailsBinding.tvMainDesc.setText(R.string.all_files_sent);
             fragmentSendExpenseDetailsBinding.pbMainDownload.setVisibility(View.GONE);
             fragmentSendExpenseDetailsBinding.tvHeading.setVisibility(View.GONE);
             mDiscoveryEngine.disconnectAll();
             isTransfer = false;
             return;
         }
         try {
             mFileName = mFiles.get(0).getName();
             filePayload = Data.fromFile(mFiles.get(0));
             mFiles.remove(0);
         } catch (FileNotFoundException e) {
             Log.e(TAG, "File not found", e);
             return;
         }
         filenameMsg = Data.fromBytes(mFileName.getBytes(StandardCharsets.UTF_8));
         Log.d(TAG, "Send filename: " + mFileName);
         mTransferEngine.sendData(mRemoteEndpointId, filenameMsg);
         Log.d(TAG, "Send Payload.");
         mTransferEngine.sendData(mRemoteEndpointId, filePayload);
     }

     private void renameFile() {
         if (incomingFile == null) {
             Log.d(TAG, "incomingFile is null");
             return;
         }
         File rawFile = incomingFile.asFile().asJavaFile();
         Log.d(TAG, "raw file: " + rawFile.getAbsolutePath());
         File targetFileName = new File(rawFile.getParentFile(), mRcvedFilename);
         Log.d(TAG, "rename to : " + targetFileName.getAbsolutePath());
         Uri uri = incomingFile.asFile().asUri();
         if (uri == null) {
             boolean result = rawFile.renameTo(targetFileName);
             if (!result) {
                 Log.e(TAG, "rename failed");
             } else {
                 Log.e(TAG, "rename Succeeded ");
             }
         } else {
             try {
                 openStream(uri, targetFileName);
             } catch (IOException e) {
                 Log.e(TAG, e.toString());
             } finally {
                 delFile(uri, rawFile);
             }
         }
     }

     private void openStream(Uri uri, File targetFileName) throws IOException {
         InputStream in = mContext.getContentResolver().openInputStream(uri);
         Log.e(TAG, "open input stream successfuly");
         try {
             copyStream(in, new FileOutputStream(targetFileName));
             Log.e(TAG, "copyStream successfuly");
         } catch (IOException e) {
             Log.e(TAG, e.toString());
         } finally {
             in.close();
         }
     }

     private void copyStream(InputStream in, OutputStream out) throws IOException {
         try {
             byte[] buffer = new byte[1024];
             int read;
             while ((read = in.read(buffer)) != -1) {
                 out.write(buffer, 0, read);
             }
             out.flush();
         } finally {
             out.close();
         }
     }

     private void delFile(Uri uri, File payloadfile) {
         //删除源文件。
         mContext.getContentResolver().delete(uri, null, null);
         if (!payloadfile.exists()) {
             Log.e(TAG, "delete original file by uri successfully");
         } else {
             Log.e(TAG, "delete  original file by uri failed and try to delete it by File delete");
             payloadfile.delete();
             if (payloadfile.exists()) {
                 Log.e(TAG, "fail to delete original file");
             } else {
                 Log.e(TAG, "delete original file successfully");
             }
         }
     }

     private void showProgressSpeedReceiver(TransferStateUpdate update) {
         long transferredBytes = update.getBytesTransferred();
         long totalBytes = update.getTotalBytes();
         long curTime = System.currentTimeMillis();
         Log.d(TAG, "Transfer in progress. Transferred Bytes: "
                 + transferredBytes + " Total Bytes: " + totalBytes);
         fragmentFileDetailsBinding.pbMainDownload.setProgress((int) (transferredBytes * 100 / totalBytes));
         if (mStartTime == 0) {
             mStartTime = curTime;
         }
         if (curTime != mStartTime) {
             mSpeed = ((float) transferredBytes) / ((float) (curTime - mStartTime)) / 1000;
             java.text.DecimalFormat myformat = new java.text.DecimalFormat("0.00");
             mSpeedStr = myformat.format(mSpeed);
             fragmentFileDetailsBinding.tvMainDesc.setText(new StringBuilder().append("Transfer in Progress. Speed: ").append(mSpeedStr).append("MB/s."));
         }
         if (transferredBytes == totalBytes) {
             mStartTime = 0;
         }
     }

     private void init() {
         if (fragmentSendExpenseDetailsBinding != null) {
             fragmentSendExpenseDetailsBinding.pbMainDownload.setProgress(0);
             fragmentSendExpenseDetailsBinding.pbMainDownload.setVisibility(View.GONE);
             fragmentSendExpenseDetailsBinding.tvMainDesc.setText("");
             fragmentSendExpenseDetailsBinding.barcodeImage.setVisibility(View.GONE);
         }
         mDiscoveryEngine.disconnectAll();
         mDiscoveryEngine.stopScan();
         mDiscoveryEngine.stopBroadcasting();
         mFiles.clear();
     }
 }
初始化用于MainActivity的NearByAgent类:
nearbyAgent = new NearbyAgent(this);
 
在SendExpenseDetailsFragment中发送文件码:
 
((MainActivity) getActivity()).nearbyAgent.sendFile(new File(getArguments().getString("mValues")), fragmentSendExpenseDetailsBinding);
 
 
 
在FileDetailsFragment中接收文件:
((MainActivity) getActivity()).nearbyAgent.receiveFile(fragmentFileDetailsBinding, filesArrayList, groupAdapter);
 
在MainActivity的onActivityResult中获取结果。
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
     switch (requestCode) {
         case NearbyAgent.REQUEST_CODE_SCAN_ONE:
             Log.d("data:", "1");
          nearbyAgent.onScanResult(data);
             break;
         default:
             break;
     }
     super.onActivityResult(requestCode, resultCode, data);
 }
 
 
使用近距离数据通信服务下载数据:
 
 
/**
AccountRepository类
  * 初始化Network Kit
 */
@Override
protected void initManager() {
     //下载manager。
     downloadManager = new DownloadManager.Builder("downloadManager")
             .build(context);

     callback = new FileRequestCallback() {
         @Override
         public GetRequest onStart(GetRequest request) {
             return request;
         }

         @Override
         public void onProgress(GetRequest request, Progress progress) {
             Log.i(TAG, "onProgress:" + progress);
         }

         @Override
         public void onSuccess(Response<GetRequest, File, Closeable> response) {
             String filePath = "";
             if (response.getContent() != null) {
                 filePath = response.getContent().getAbsolutePath();
             }
             Log.i(TAG, "onSuccess" + " for " + filePath);
         }

         @Override
         public void onException(GetRequest getRequest, NetworkException e, Response<GetRequest, File, Closeable> response) {
             if (e instanceof Exception) {
                 String errorMsg = "download exception for paused or canceled";
                 Log.w(TAG, errorMsg);
             } else {
                 String errorMsg = "download exception for request:" + getRequest.getId() +
                         "\n\ndetail : " + e.getMessage();
                 if (e.getCause() != null) {
                     errorMsg += " , cause : " +
                             e.getCause().getMessage();
                 }
                 Log.e(TAG, errorMsg);
             }
         }
     };
 }

 
 
@Override
public void download() {
     imageDownload(context);
 }

private void imageDownload(Context context) {
     if (downloadManager == null) {
         Log.e(TAG, "can not download without init");
         return;
     }
     
     String downloadFilePath = context.getObbDir().getPath() + File.separator + "acc111.jpg";
     getRequest = DownloadManager.newGetRequestBuilder()
             .filePath(downloadFilePath)
             .url(Common.getUrlRequest())
             .build();
     Result result = downloadManager.start(getRequest, callback);
     checkResult(result);
 }

九、打包和测试

1、启动Android Studio,点击运行按钮,在手机或模拟器上运行您的应用。点击登录按钮登录您的应用。

cke_498185.pngcke_533595.png

2、登录成功后,展示群界面。点击“+“图标新建群。

cke_589817.pngcke_624120.png

3、群在创建完成后将被插入到云数据库中,用户进入主界面,显示最新群列表。

4、在列表中点击一个群,打开群详情界面。

cke_775841.png

5、点击任意一条列表中的账单或收支数据,进入详情界面。

cke_830907.pngcke_866251.png

6、点击分享按钮,将账单详情以文件形式发送给附近的好友。该操作使用近距离数据通信服务,无需使用到手机流量和wifi。

cke_916339.png

7、查看收到的账单文件。

cke_969577.png

8、点击接收按钮接收文件。

cke_1025092.png

十、恭喜您

祝贺您,您已成功构建一款SplitBill应用并学会了:

  • AppGallery Connect中配置云数据库和云存储。

  • 在Android Studio中集成多个HMS Core服务并构建一款SplitBill应用。

十一、参考

参考如下文档获取更多信息:

点击此处下载源码。

声明:本codelab实现多个HMS Core服务在单个项目中的集成,供您参考。您需要验证确保相关开源代码的安全合法合规。

欲了解更多更全技术文章,欢迎访问https://developer.huawei.com/consumer/cn/forum/?ha_source=zzh

标签:Core,Log,void,HMS,TAG,SplitBill,new,import,public
From: https://www.cnblogs.com/developer-huawei/p/16917269.html

相关文章