简介

HUAWEI Wireless Kit是华为为开发者提供的无线传输服务,使应用和手机底层通信的QoE信息互相感知。开发者通过集成Wireless Kit可以让应用通信体验更顺畅,提升用户的粘性。

您将会学到什么

硬件要求

软件要求

需要的知识点

集成HUAWEI HMS Core能力,需要完成以下准备工作:

具体操作,请按照《HUAWEI HMS Core集成准备》中详细说明来完成。

添加AppGallery Connect配置文件

  1. 登录AppGallery Connect网站,点击"我的项目"。
  2. 在项目列表中找到您的项目,在项目中点击需要集成HMS Core SDK的应用。
  3. 在"项目设置"页面的"应用"区域,点击"agconnect-services.json"下载配置文件。
  4. 将"agconnect-services.json"文件拷贝到应用级根目录下。

添加SDK依赖
1. 在项目级的build.gradle文件中,添加HUAWEI agcp插件以及Maven代码库。

buildscript { repositories { ... maven { url https://developer.huawei.com/repo/' } } dependencies { ... classpath 'com.huawei.agconnect:agcp:1.4.1.300' } } allprojects { repositories { ... maven { url https://developer.huawei.com/repo/' } } }

2. 在应用级app目录下的build.gradle中配置Maven依赖。

1)打开应用级的"build.gradle"文件。

2)在文件头apply plugin: 'com.android.application'下一行添加如下配置。

apply plugin: 'com.huawei.agconnect'

3)在"dependencies"中添加如下编译依赖。

dependencies { implementation 'com.huawei.hms:wireless:{version}' }

{version}替换为实际的版本号,具体版本号请参见版本更新说明。例如:

implementation 'com.huawei.hms:wireless:5.0.1.305'

3. 配置混淆脚本。
开发者编译APK前需要配置混淆配置文件,避免混淆HMS Core SDK导致功能异常。
Android Studio开发环境里的配置文件是"proguard-rules.pro"

1)打开工程的混淆配置文件。

2)加入排除HMS Core SDK的混淆配置。

-ignorewarnings -keepattributes *Annotation* -keepattributes Exceptions -keepattributes InnerClasses -keepattributes Signature -keepattributes SourceFile,LineNumberTable -keep class com.hianalytics.**{*;} -keep class com.huawei.updatesdk.**{*;} -keep class com.huawei.hms.**{*;}

3)如果开发者使用了AndResGuard,需要在混淆配置文件中加入AndResGuard允许清单。

"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*"

本节将指引您绑定AIDL接口IQoEService对应的Service,快速接入Wireless Kit获取网络QoE反馈。

1. 绑定服务

获取NetworkQoeClient对象。利用getNetworkQoeServiceIntent接口获取intent,并绑定IQoeService服务。若intent获取失败,App无法使用IQoeService服务。

// 根据需要添加Android相关类 import com.huawei.hmf.tasks.OnFailureListener; import com.huawei.hmf.tasks.OnSuccessListener; import com.huawei.hms.common.ApiException; import com.huawei.hms.wireless.IQoeService; import com.huawei.hms.wireless.NetworkQoeClient; import com.huawei.hms.wireless.WirelessClient; import com.huawei.hms.wireless.WirelessResult; public class NetworkQoeActivity extends AppCompatActivity { private NetworkQoeClient networkQoeClient; private IQoeService qoeService; private ServiceConnection mSrcConn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { qoeService = IQoeService.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { qoeService = null; } }; @Override protected void onCreate(Bundle savedInstanceState) { networkQoeClient = WirelessClient.getNetworkQoeClient(NetworkPredictActivity.this); if (networkQoeClient != null) { networkQoeClient.getNetworkQoeServiceIntent() .addOnSuccessListener(new OnSuccessListener<WirelessResult>() { @Override public void onSuccess(WirelessResult wirelessResult) { Intent intent = wirelessResult.getIntent(); if (intent == null) { return; } NetworkQoeActivity.this.bindService(intent, mSrcConn, Context.BIND_AUTO_CREATE); } }) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { if (e instanceof ApiException) { ApiException ex = (ApiException) e; int errCode = ex.getStatusCode(); } } }); } } }

2. 网络QoE信息注册回调

a)注册网络QoE信息回调,callBack里包含对网络QoE关键数据解析。

// 根据需要添加Android相关类 import com.huawei.hmf.tasks.OnFailureListener; import com.huawei.hmf.tasks.OnSuccessListener; import com.huawei.hms.common.ApiException; import com.huawei.hms.wireless.IQoeCallBack; import com.huawei.hms.wireless.IQoeService; import com.huawei.hms.wireless.NetworkQoeClient; import com.huawei.hms.wireless.WirelessClient; import com.huawei.hms.wireless.WirelessResult; public class NetworkQoeActivity extends AppCompatActivity { private static final String TAG = "networkQoe"; private static final int NETWORK_QOE_INFO_TYPE = 0; private int[] channelIndex = new int[4]; private int[] uLRtt = new int[4]; private int[] dLRtt = new int[4]; private int[] uLBandwidth = new int[4]; private int[] dLBandwidth = new int[4]; private int[] uLRate = new int[4]; private int[] dLRate = new int[4]; private int[] netQoeLevel = new int[4]; private int[] uLPkgLossRate = new int[4]; private IQoeService qoeService; private IQoeCallBack callBack = new IQoeCallBack.Stub() { @Override public void callBack(int type, Bundle qoeInfo) throws RemoteException { if (qoeInfo == null || type != NETWORK_QOE_INFO_TYPE) { Log.e(TAG, "callback failed.type:" + type); return; } int channelNum = 0; if (qoeInfo.containsKey("channelNum")) { channelNum = qoeInfo.getInt("channelNum"); } String channelQoe = String.valueOf(channelNum); for (int i = 0; i < channelNum; i++) { uLRtt[i] = qoeInfo.getInt("uLRtt" + i); dLRtt[i] = qoeInfo.getInt("dLRtt" + i); uLBandwidth[i] = qoeInfo.getInt("uLBandwidth" + i); dLBandwidth[i] = qoeInfo.getInt("dLBandwidth" + i); uLRate[i] = qoeInfo.getInt("uLRate" + i); dLRate[i] = qoeInfo.getInt("dLRate" + i); netQoeLevel[i] = qoeInfo.getInt("netQoeLevel" + i); uLPkgLossRate[i] = qoeInfo.getInt("uLPkgLossRate" + i); channelIndex[i] = qoeInfo.getInt("channelIndex" + i); // channelQoe可以通过EditText显示在用户界面 channelQoe += "," + channelIndex[i] + "," + uLRtt[i] + "," + dLRtt[i] + "," + uLBandwidth[i] + "," + dLBandwidth[i] + "," + uLRate[i] + "," + dLRate[i] + "," + netQoeLevel[i] + "," + uLPkgLossRate[i]; } } }; @Override protected void onCreate(Bundle savedInstanceState) { if (qoeService != null) { try { int ret = qoeService.registerNetQoeCallBack("com.huawei.hms.wirelessdemo",callBack); } catch (RemoteException ex) { // 这里可以添加打印 } } } }

b)去注册网络QoE信息回调,callBack需要和注册时一致。去注册后,App的callBack流程不再执行。

public class NetworkQoeActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { int ret = 0; if (qoeService != null) { try { ret = qoeService.unRegisterNetQoeCallBack("com.huawei.hms.wirelessdemo", callBack); } catch (RemoteException ex) { // 这里可以添加打印 } } } }

c)获取实时QoE信息。

public class NetworkQoeActivity extends AppCompatActivity { private int[] channelIndex = new int[4]; private int[] uLRtt = new int[4]; private int[] dLRtt = new int[4]; private int[] uLBandwidth = new int[4]; private int[] dLBandwidth = new int[4]; private int[] uLRate = new int[4]; private int[] dLRate = new int[4]; private int[] netQoeLevel = new int[4]; private int[] uLPkgLossRate = new int[4]; private IQoeService qoeService; @Override protected void onCreate(Bundle savedInstanceState) { if (qoeService != null) { try { Bundle qoeInfo = qoeService.queryRealTimeQoe("com.huawei.hms.wirelessdemo"); if (qoeInfo == null) { return; } int channelNum = qoeInfo.getInt("channelNum"); for (int i = 0; i < channelNum; i++) { uLRtt[i] = qoeInfo.getInt("uLRtt" + i); dLRtt[i] = qoeInfo.getInt("dLRtt" + i); uLBandwidth[i] = qoeInfo.getInt("uLBandwidth" + i); dLBandwidth[i] = qoeInfo.getInt("dLBandwidth" + i); uLRate[i] = qoeInfo.getInt("uLRate" + i); dLRate[i] = qoeInfo.getInt("dLRate" + i); netQoeLevel[i] = qoeInfo.getInt("netQoeLevel" + i); uLPkgLossRate[i] = qoeInfo.getInt("uLPkgLossRate" + i); } } catch (RemoteException ex) { // 这里可以添加打印 } } } }

3. 解绑服务

使用Android服务机制,App解绑IQoeService。

NetworkPredictActivity.this.unbindService(mSrcConn); //mSrvConn要与绑定时的ServiceConnection对象保持一致。在onCreate函数或者onDestroy函数中调用。

1. 双击Android Studio的Gradle的"assembleDebug" ,运行Android Studio工程打包生成APK,并安装在测试手机上,手机需要打开数据业务,并可以连接Internet。

2. 安装到手机上后,运行APK。

3. 点击"NETWORKQOE"按钮,进入"Network qoe"界面。

a)点击"BIND SERVICE"按钮,TextView显示"Connected",代表绑定成功。

b)点击"REGISTER CALLBACK"按钮,TextView显示"0",代表注册成功。这时,"UNBIND SERVICE"按钮上面的TextView会显示由数字、逗号和负号等字符连接的字符串。字符串含义如下:

第一个逗号前的数字代表当前手机连接的信道数,0表示没有有效的信道指示,1-4为有效值范围。一组信道的参数有9个,按先后顺序依次是标识、上行时延、下行时延、上行带宽、下行带宽、上行速率、下行速率、QoE等级和上行丢包率。参数含义更详细的介绍请见API参考

c)点击 "QUERY REAL TIME QOE"按钮,注册状态时,"QUERY REAL TIME QOE"按钮下面TextView显示同上述注册时显示的字串相同;去注册状态时,显示0。

d)点击"UNREGISTER CALLBACK"按钮,TextView显示"0",代表去注册成功。这时,"UNBIND SERVICE"按钮上面的TextView会显示"0"。

e)点击"UNBIND SERVICE"按钮,"BIND SERVICE"按钮后面的TextView显示"Disconnected"。

4. 点击"REPORTAPPQUALITY"按钮,进入"Report app quality"界面。该界面显示调用者业务通信质量信息。

a)eventId为int类型数值,表示应用异常事件,数值含义为:

b)direction为int类型数值,表示数据传输方向,数值含义为:

c)netReason为String类型数值,表示网络相关错误码,数值含义为:

如果问题场景不在上述范围内,用户可自己填写其他值,如果String字串由整数构成,整数值需要大于100。

5.点击"NETWORKPREDICTION"按钮,进入"Network prediction"界面。该界面显示弱信号预测广播事件。

1)第一个下划线数值表示即将进入弱信号区域的时间enteringTime;
2)第二个下划线数值表示即将离开弱信号区域的时间leavingTime;
3)通知标志typeValue的含义为:当typeValue为1时,表示经过enteringTime时间后,移动终端将进入弱信号区域;当enteringTime到达之后,再经过leavingTime的时间,移动终端会离开弱信号区域。当typeValue为0时,取消上次消息的执行且忽略本次消息中的enteringTime和leavingTime;

MainActivity.java

package com.huawei.hms.wirelessdemo; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.Button; import androidx.appcompat.app.AppCompatActivity; /** * Wireless kit test demo * * @since 2020-07-09 */ public class MainActivity extends AppCompatActivity { private Button reportAppQuality; private Button networkPrediction; private Button networkQoe; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); networkQoe = findViewById(R.id.NetworkQoe); // Click NetworkQoe button to start NetworkQoeActivity networkQoe.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(MainActivity.this, NetworkQoeActivity.class); startActivity(intent); } }); } }

NetworkQoeActivity.java

package com.huawei.hms.wirelessdemo; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; import androidx.appcompat.app.AppCompatActivity; import com.huawei.hmf.tasks.OnFailureListener; import com.huawei.hmf.tasks.OnSuccessListener; import com.huawei.hms.common.ApiException; import com.huawei.hms.wireless.IQoeCallBack; import com.huawei.hms.wireless.IQoeService; import com.huawei.hms.wireless.NetworkQoeClient; import com.huawei.hms.wireless.WirelessClient; import com.huawei.hms.wireless.WirelessResult; /** * Network qoe test demo * * @since 2020-07-09 */ public class NetworkQoeActivity extends AppCompatActivity { private static final String TAG = "networkQoe"; private static final int NETWORK_QOE_INFO_TYPE = 0; private Button getQoeButton; private Button registerButton; private Button unRegisterButton; private Button showQoeDetailButton; private Button cancelQoeButton; private EditText getQoeStateText; private EditText registerStateText; private EditText unregisterStateText; private EditText showQoeDetailsText; private EditText callQoeDetails; private int[] channelIndex = new int[4]; private int[] uLRtt = new int[4]; private int[] dLRtt = new int[4]; private int[] uLBandwidth = new int[4]; private int[] dLBandwidth = new int[4]; private int[] uLRate = new int[4]; private int[] dLRate = new int[4]; private int[] netQoeLevel = new int[4]; private int[] uLPkgLossRate = new int[4]; private IQoeService qoeService = null; private ServiceConnection srcConn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { qoeService = IQoeService.Stub.asInterface(service); getQoeStateText.setText("Connected"); } @Override public void onServiceDisconnected(ComponentName name) { qoeService = null; Log.i(TAG, "onServiceDisConnected."); getQoeStateText.setText("Disconnected"); } }; private IQoeCallBack callBack = new IQoeCallBack.Stub() { @Override public void callBack(int type, Bundle qoeInfo) throws RemoteException { if (qoeInfo == null || type != NETWORK_QOE_INFO_TYPE) { Log.e(TAG, "callback failed.type:" + type); return; } int channelNum = 0; if (qoeInfo.containsKey("channelNum")) { channelNum = qoeInfo.getInt("channelNum"); } String channelQoe = String.valueOf(channelNum); for (int i = 0; i < channelNum; i++) { uLRtt[i] = qoeInfo.getInt("uLRtt" + i); dLRtt[i] = qoeInfo.getInt("dLRtt" + i); uLBandwidth[i] = qoeInfo.getInt("uLBandwidth" + i); dLBandwidth[i] = qoeInfo.getInt("dLBandwidth" + i); uLRate[i] = qoeInfo.getInt("uLRate" + i); dLRate[i] = qoeInfo.getInt("dLRate" + i); netQoeLevel[i] = qoeInfo.getInt("netQoeLevel" + i); uLPkgLossRate[i] = qoeInfo.getInt("uLPkgLossRate" + i); channelIndex[i] = qoeInfo.getInt("channelIndex" + i); channelQoe += "," + channelIndex[i] + "," + uLRtt[i] + "," + dLRtt[i] + "," + uLBandwidth[i] + "," + dLBandwidth[i] + "," + uLRate[i] + "," + dLRate[i] + "," + netQoeLevel[i] + "," + uLPkgLossRate[i]; } Log.i(TAG, channelQoe); callQoeDetails.setText(channelQoe); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_network_qoe); this.setTitle("Network qoe"); initWidget(); // Bind QoeService bindQoeService(); // Register network qoe callback registerButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick (View view) { int ret = 0; if (qoeService != null) { try { ret = qoeService.registerNetQoeCallBack("com.huawei.hms.wirelessdemo", callBack); registerStateText.setText(Integer.toString(ret)); } catch (RemoteException ex) { Log.e(TAG, "no registerNetQoeCallback api"); } } } }); // Unregister network qoe callback unRegisterButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick (View view) { int ret = 0; if (qoeService != null) { try { ret = qoeService.unRegisterNetQoeCallBack("com.huawei.hms.wirelessdemo", callBack); unregisterStateText.setText(Integer.toString(ret)); } catch (RemoteException ex) { Log.e(TAG, "no unregisterNetQoeCallback api"); } } } }); // Query real time qoe information showRealTimeQoeInfo(); // Unbind QoeService cancelQoeButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick (View view) { if (qoeService != null) { NetworkQoeActivity.this.unbindService(srcConn); qoeService = null; getQoeStateText.setText("Disconnected"); } } }); } private void initWidget() { getQoeButton = findViewById(R.id.ConnectQoe); registerButton = findViewById(R.id.registerQoe); unRegisterButton = findViewById(R.id.unRegisterQoe); showQoeDetailButton = findViewById(R.id.getQoeData); cancelQoeButton = findViewById(R.id.cancleService); getQoeStateText = findViewById(R.id.ConnectQoeState); registerStateText = findViewById(R.id.registerState); unregisterStateText = findViewById(R.id.unregisterState); showQoeDetailsText = findViewById(R.id.getQoeDataContext); callQoeDetails = findViewById(R.id.callQoeDetails); } private void bindQoeService() { getQoeButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { NetworkQoeClient networkQoeClient = WirelessClient.getNetworkQoeClient(NetworkQoeActivity.this); if (networkQoeClient != null) { networkQoeClient.getNetworkQoeServiceIntent() .addOnSuccessListener(new OnSuccessListener<WirelessResult>() { @Override public void onSuccess(WirelessResult wirelessResult) { Intent intent = wirelessResult.getIntent(); if (intent == null) { Log.i(TAG, "intent is null."); return; } NetworkQoeActivity.this.bindService(intent, srcConn, Context.BIND_AUTO_CREATE); } }) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception exception) { if (exception instanceof ApiException) { ApiException ex = (ApiException) exception; int errCode = ex.getStatusCode(); Log.e(TAG, "Get intent failed:" + errCode); } } }); } } }); } private void showRealTimeQoeInfo() { showQoeDetailButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick (View view) { if (qoeService != null) { try { Bundle qoeInfo = qoeService.queryRealTimeQoe("com.huawei.hms.wirelessdemo"); if (qoeInfo == null) { Log.e(TAG, "queryRealTimeQoe is empty."); return; } int channelNum = 0; if (qoeInfo.containsKey("channelNum")) { channelNum = qoeInfo.getInt("channelNum"); } String channelQoe = String.valueOf(channelNum); for (int i = 0; i < channelNum; i++) { uLRtt[i] = qoeInfo.getInt("uLRtt" + i); dLRtt[i] = qoeInfo.getInt("dLRtt" + i); uLBandwidth[i] = qoeInfo.getInt("uLBandwidth" + i); dLBandwidth[i] = qoeInfo.getInt("dLBandwidth" + i); uLRate[i] = qoeInfo.getInt("uLRate" + i); dLRate[i] = qoeInfo.getInt("dLRate" + i); netQoeLevel[i] = qoeInfo.getInt("netQoeLevel" + i); uLPkgLossRate[i] = qoeInfo.getInt("uLPkgLossRate" + i); channelIndex[i] = qoeInfo.getInt("channelIndex" + i); channelQoe += "," + channelIndex[i] + "," + uLRtt[i] + "," + dLRtt[i] + "," + uLBandwidth[i] + "," + dLBandwidth[i] + "," + uLRate[i] + "," + dLRate[i] + "," + netQoeLevel[i] + "," + uLPkgLossRate[i]; } Log.i(TAG, channelQoe); showQoeDetailsText.setText(channelQoe); } catch (RemoteException exception) { Log.e(TAG, "no unregisterNetQoeCallback api"); } } } }); } }

干得好,您已经成功完成了Codelab并学到了:

您可以阅读下面链接,了解更多相关的信息。
请参见相关文档
您可以点击下方按钮下载源码。

源码下载

已复制代码