HUAWEI Wireless Kit是华为为开发者提供的无线传输服务,使应用和手机底层通信的QoE信息互相感知。开发者通过集成Wireless Kit可以让应用通信体验更顺畅,提升用户的粘性。
集成HUAWEI HMS Core能力,需要完成以下准备工作:
具体操作,请按照《HUAWEI HMS Core集成准备》中详细说明来完成。
添加AppGallery Connect配置文件
添加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反馈。
获取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();
}
}
});
}
}
}
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) {
// 这里可以添加打印
}
}
}
}
使用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并学到了:
您可以阅读下面链接,了解更多相关的信息。
请参见相关文档。
您可以点击下方按钮下载源码。