最近应公司项目需求接入华为联运游戏开发的SDK,特记录接入过程的那些坑!!
官网接入文档:
后台申请的过程自行到官网查看,此处只介绍接入流程。
注意事项:
1.后台配置的SHA256必须要和打包的签名文件一致,debug也要用这个签名文件去跑
SHA256生成:keytool -list -v -keystore + 秘钥绝对路径
2.包名要以.huawei后缀 例:com.xxx.huawei
接入流程:
1.将“agconnect-services.json”文件拷贝到应用级根目录下:
2. 在build.gradle(project)添加HUAWEI agcp插件以及Maven代码库:
buildscript {
repositories {
google()
jcenter()
maven {url 'https://developer.huawei.com/repo/'}
}
dependencies {
...
classpath 'com.huawei.agconnect:agcp:1.4.2.301'
}
}
allprojects {
repositories {
google()
jcenter()
maven {url 'https://developer.huawei.com/repo/'}
}
}
3.在build.gradle(app)添加依赖:
dependencies {
......
implementation 'com.huawei.hms:base:5.0.5.300'
implementation 'com.huawei.hms:hwid:5.0.5.301'
implementation 'com.huawei.hms:iap:5.0.4.301'
implementation 'com.huawei.hms:game:5.0.4.302'
implementation 'com.huawei.hms:hianalytics:5.0.5.301'
}
具体版本请参考官网
注意:如果还需接入华为Ads的不需要再加入广告接入文档中的base和ppskit,否则会闪退
4.在build.gradle(app)文件头apply plugin: 'com.android.application’下一行添加如下配置:
apply plugin: 'com.huawei.agconnect'
5.多语言设置:
参考官网语言设置:
6.混淆:
Android Studio开发环境里的配置文件是“proguard-rules.pro”
-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.**{*;}
-keep interface com.huawei.hms.analytics.type.HAEventType{*;}
-keep interface com.huawei.hms.analytics.type.HAParamType{*;}
-keep class com.huawei.hms.analytics.HiAnalyticsInstance{*;}
-keep class com.huawei.hms.analytics.HiAnalytics{*;}
初始化:
在Application的onCreate方法中添加如下代码,用于注册Activity的回调监听
public class MyApplication extends Application{
@Override
public void onCreate(){
super.onCreate();
HuaweiMobileServicesUtil.setApplication(this);
}
}
Manifest文件中配置:
在Activity onCreate中调用:
private void init() {
JosAppsClient appsClient = JosApps.getJosAppsClient(this);
appsClient.init();
Log.i(TAG, "init success");
}
登录:
1.账号登录:
MainActivity.LOGIN_CODE 为 8000
public void signIn(Activity activity) {
Log.e(TAG, "signIn----:");
HuaweiIdAuthParams authParams = new HuaweiIdAuthParamsHelper(HuaweiIdAuthParams.DEFAULT_AUTH_REQUEST_PARAM).setAuthorizationCode().createParams();
HuaweiIdAuthService service = HuaweiIdAuthManager.getService(activity, authParams);
activity.startActivityForResult(service.getSignInIntent(), MainActivity.LOGIN_CODE);
}
登录授权完成后处理登录结果:
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
//授权登录结果处理,从AuthHuaweiId中获取Authorization Code
super.onActivityResult(requestCode, resultCode, data);
if (LOGIN_CODE == requestCode) {
Task<AuthHuaweiId> authHuaweiIdTask = HuaweiIdAuthManager.parseAuthResultFromIntent(data);
if (authHuaweiIdTask.isSuccessful()) {
//登录成功,获取用户的华为帐号信息和Authorization Code
AuthHuaweiId huaweiAccount = authHuaweiIdTask.getResult();
HuaWeiSDKController.getInstance().getCurrentPlayer(this);//登录成功,获取playerId
} else {
//登录失败
Log.e(TAG, "sign in failed:" + ((ApiException) authHuaweiIdTask.getException()).getStatusCode());
}
}
}
2.静默登录:
/**
* sdk静默登录
* @param activity
*/
public void silenceIn(final Activity activity){
Log.e(TAG, "login---");
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
authParams = new HuaweiIdAuthParamsHelper(HuaweiIdAuthParams.DEFAULT_AUTH_REQUEST_PARAM).createParams();
HuaweiIdAuthService service = HuaweiIdAuthManager.getService(activity, authParams);
Task<AuthHuaweiId> task = service.silentSignIn();
task.addOnSuccessListener(new OnSuccessListener<AuthHuaweiId>() {
@Override
public void onSuccess(AuthHuaweiId authHuaweiId) {
//获取华为帐号信息
Log.e(TAG, "displayName:" + authHuaweiId.getDisplayName());
getCurrentPlayer(activity);//登录成功,获取playerId
}
});
task.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
//登录失败,您可以尝试使用getSignInIntent()方法显式登录
if (e instanceof ApiException) {
ApiException apiException = (ApiException)e;
Log.e(TAG, "sign failed status:" + apiException.getStatusCode());
/**
* 静默登录失败
* 调用显式登录
*/
signIn(activity);
}
}
});
}
});
}
3.登录成功后,从Player对象中获取玩家信息:
/**
* 登录成功后调
* 获取当前登录的玩家对象
* 从Player对象中获取玩家信息。
* @param activity
*/
public void getCurrentPlayer(Activity activity) {
//PlayersClientImpl playersClient = (PlayersClientImpl) Games.getPlayersClient(activity);
Task<Player> task = client.getCurrentPlayer();
task.addOnSuccessListener(new OnSuccessListener<Player>() {
@Override
public void onSuccess(Player player) {
playerId = player.getPlayerId();
EnterGame();//进入游戏,调用防沉迷监听,事件上传
WeakReference_Timer.getInstance().intentTimer(activity);//每15分钟调一次
Log.e(TAG,"onSuccess--playerId = "+player.getPlayerId());
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof ApiException) {
String result = "rtnCode:" + ((ApiException) e).getStatusCode();
Log.e(TAG,"onFailure--result = "+result);
}
}
});
}
浮标:
注意事项
发布地区包含中国大陆的联运游戏,要求必须集成游戏浮标,游戏的所有界面都需要展示游戏浮标。
对于EMUI 9.1.1以下版本的华为设备,您需要按照本文档要求集成游戏浮标,并且设备必须安装9.0以上版本华为应用市场客户端才能展示浮标。
对于EMUI 9.1.1及以上版本的华为设备,HMS Core(APK)会自动展示游戏浮标而忽略本接口的请求,您无需关注
BuoyClient 实例:
BuoyClient buoyClient = Games.getBuoyClient(this);
展示浮标:
buoyClient.showFloatWindow();
隐藏浮标:
buoyClient.hideFloatWindow();
防沉迷:
/**
* 检测是否已实名
*/
public void preAddiction(){
Log.e(TAG, "PreAddiction---");
client.setGameTrialProcess(new GameTrialProcess() {
@Override
public void onTrialTimeout() {
//试玩时间结束
Log.e(TAG, "PreAddiction---onTrialTimeout");
}
@Override
public void onCheckRealNameResult(boolean hasRealName) {
Log.e(TAG, "PreAddiction---hasRealName = "+hasRealName);
if (hasRealName) {
// 已实名,继续后续的游戏登录处理
return;
}
//未实名,建议您提示玩家后退出游戏或引导玩家重新登录并实名认证
}
});
}
防沉迷监控:
/**
* 防沉迷监听
* 事件上传
* 进入游戏
*/
public void EnterGame(){
Log.e(TAG, "EnterGame---");
if (TextUtils.isEmpty(playerId)) {
Log.e(TAG, "GetCurrentPlayer first.");
return;
}
String uid = UUID.randomUUID().toString();
Task<String> task = client.submitPlayerEvent(playerId, uid, "GAMEBEGIN");
task.addOnSuccessListener(new OnSuccessListener<String>() {
@Override
public void onSuccess(String jsonRequest) {
try {
JSONObject data = new JSONObject(jsonRequest);
sessionId = data.getString("transactionId");
} catch (JSONException e) {
Log.e(TAG,"parse jsonArray meet json exception");
return;
}
Log.e(TAG,"submitPlayerEvent traceId: " + jsonRequest);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof ApiException) {
String result = "rtnCode:" + ((ApiException) e).getStatusCode();
Log.e(TAG,"EnterGame--"+result);
}
}
});
}
/**
* 防沉迷监听
* 事件上传
* 退出游戏
*/
public void ExitGame(){
if (TextUtils.isEmpty(playerId)) {
Log.e(TAG,"GetCurrentPlayer first.");
return;
}
if (TextUtils.isEmpty(sessionId)) {
Log.e(TAG,"SessionId is empty.");
return;
}
Task<String> task = client.submitPlayerEvent(playerId, sessionId, "GAMEEND");
task.addOnSuccessListener(new OnSuccessListener<String>() {
@Override
public void onSuccess(String s) {
Log.e(TAG,"submitPlayerEvent traceId: " + s);
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof ApiException) {
String result = "rtnCode:" + ((ApiException) e).getStatusCode();
Log.e(TAG,"ExitGame--"+result);
}
}
});
}
内支付
MainActivity.PAYMENT_CODE 为 6000
/**
* 判断是否支持应用内支付
* @param activity
*/
public void isSupportPay(final Activity activity){
Log.e(TAG, "pay---");
// 获取调用接口的Activity对象
Task<IsEnvReadyResult> task = Iap.getIapClient(activity).isEnvReady();
task.addOnSuccessListener(new OnSuccessListener<IsEnvReadyResult>() {
@Override
public void onSuccess(IsEnvReadyResult result) {
// 获取接口请求的结果
Log.e(TAG, "isSupportPay-支持应用内支付---");
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof IapApiException) {
IapApiException apiException = (IapApiException) e;
Status status = apiException.getStatus();
if (status.getStatusCode() == OrderStatusCode.ORDER_HWID_NOT_LOGIN) {
// 未登录帐号
Log.e(TAG, "isSupportPay-登录帐号---");
if (status.hasResolution()) {
try {
// 启动IAP返回的登录页面
Log.e(TAG, "isSupportPay-启动IAP返回的登录页面---");
status.startResolutionForResult(activity, MainActivity.PAYMENT_CODE);
} catch (IntentSender.SendIntentException exp) {
}
}
} else if (status.getStatusCode() == OrderStatusCode.ORDER_ACCOUNT_AREA_NOT_SUPPORTED) {
// 用户当前登录的华为帐号所在的服务地不在华为IAP支持结算的国家或地区中
Log.e(TAG, "isSupportPay-不在华为IAP支持结算的国家或地区中---");
}
}
}
});
}
/**
* 发起购买
* @param activity
*/
public void buyProduct(Activity activity){
// 构造一个PurchaseIntentReq对象
PurchaseIntentReq req = new PurchaseIntentReq();
// 通过createPurchaseIntent接口购买的商品必须是您在AppGallery Connect网站配置的商品。
req.setProductId("CProduct1");
// priceType: 0:消耗型商品; 1:非消耗型商品; 2:订阅型商品
req.setPriceType(0);
req.setDeveloperPayload("test");
// 调用createPurchaseIntent接口创建托管商品订单
Task<PurchaseIntentResult> task = Iap.getIapClient(activity).createPurchaseIntent(req);
task.addOnSuccessListener(new OnSuccessListener<PurchaseIntentResult>() {
@Override
public void onSuccess(PurchaseIntentResult result) {
// 获取创建订单的结果
Status status = result.getStatus();
if (status.hasResolution()) {
try {
// 启动IAP返回的收银台页面
Log.e(TAG, "buyProduct-启动IAP返回的收银台页面---");
status.startResolutionForResult(activity, MainActivity.PAYMENT_CODE);
} catch (IntentSender.SendIntentException exp) {
}
}
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof IapApiException) {
IapApiException apiException = (IapApiException) e;
Status status = apiException.getStatus();
int returnCode = apiException.getStatusCode();
Log.e(TAG, "buyProduct-onFailure---"+returnCode);
} else {
// 其他外部错误
Log.e(TAG, "buyProduct-其他外部错误---");
}
}
});
}
/**
* 确认交易
* @param activity
* @param inAppPurchaseData 购买信息
*/
public void confirmBuy(Activity activity,String inAppPurchaseData){
// 构造ConsumeOwnedPurchaseReq对象
ConsumeOwnedPurchaseReq req = new ConsumeOwnedPurchaseReq();
String purchaseToken = "";
try {
// purchaseToken需从购买信息InAppPurchaseData中获取
InAppPurchaseData inAppPurchaseDataBean = new InAppPurchaseData(inAppPurchaseData);
purchaseToken = inAppPurchaseDataBean.getPurchaseToken();
} catch (JSONException e) {
}
req.setPurchaseToken(purchaseToken);
// 消耗型商品发货成功后,需调用consumeOwnedPurchase接口进行消耗
Task<ConsumeOwnedPurchaseResult> task = Iap.getIapClient(activity).consumeOwnedPurchase(req);
task.addOnSuccessListener(new OnSuccessListener<ConsumeOwnedPurchaseResult>() {
@Override
public void onSuccess(ConsumeOwnedPurchaseResult result) {
// 获取接口请求结果
Log.e(TAG, "confirmBuy-获取接口请求结果---");
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof IapApiException) {
IapApiException apiException = (IapApiException) e;
Status status = apiException.getStatus();
int returnCode = apiException.getStatusCode();
Log.e(TAG, "confirmBuy-onFailure---"+returnCode);
} else {
// 其他外部错误
Log.e(TAG, "confirmBuy-其他外部错误---");
}
}
});
}
以上,此处接入流程已完成!
SDK中还有其它功能接入,具体按项目需求自行接入,此处就不再做详细介绍了。
最后附上完整demo:
华为ads sdk 完整demo
谢谢!!!