Last active
June 29, 2021 09:43
-
-
Save sandin/4fd2c1ae42eae61eee44d5c2de9db5de to your computer and use it in GitHub Desktop.
Unity项目接入华为NetworkKit说明
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.IO; | |
using UnityEngine; | |
#if UNITY_ANDROID | |
namespace HmsNetworkKitUnofficial | |
{ | |
/** | |
* 文件上传/下载任务执行过程中的回调接口。 | |
* | |
* java class: com.huawei.hms.network.file.download.api.FileRequestCallback | |
* @see https://developer.huawei.com/consumer/cn/doc/development/HMSCore-References-V5/network-file-api-callback-0000001077821946-V5#ZH-CN_TOPIC_0000001077821946__section668132695614 | |
* @see https://developer.huawei.com/consumer/cn/doc/development/HMSCore-References-V5/network-file-download-filerequestcallback-0000001077628860-V5 | |
*/ | |
public interface FileRequestCallback | |
{ | |
/** | |
* 任务开始执行时的回调。 | |
* | |
* @param request Request的子类(GetRequest或者BodyRequest)对象。 | |
*/ | |
void OnStart(GetRequest request); | |
/** | |
* 任务执行进度回调,可以获取上传/下载进度、实时速度等相关信息。 | |
* | |
* @param request Request的子类(GetRequest或者BodyRequest)对象。 | |
* @param progress 任务进度实体类。 | |
*/ | |
void OnProgress(GetRequest request, Progress progress); | |
/** | |
* 任务成功执行完的回调。 | |
* | |
* @param request Request的子类(GetRequest或者BodyRequest)对象。 | |
* @param response 最终请求结果响应实体类。 | |
*/ | |
void OnSuccess(Response response); | |
/** | |
* 任务发生异常时的回调,您主动暂停或取消同样会回调此接口。 | |
* | |
* @param request Request的子类(GetRequest或者BodyRequest)对象。 | |
* @param exception 上传/下载异常实体类。 | |
* @param response 最终请求结果响应实体类。当网络请求返回前任务出现异常,此参数有为空值的情况。 | |
*/ | |
void OnException(GetRequest request, DownloadException exception, Response response); | |
} | |
public class AndroidJavaObjectWrapper : IDisposable | |
{ | |
protected AndroidJavaObject mJavaObject; | |
public AndroidJavaObjectWrapper(AndroidJavaObject javaObject, string className = null) | |
{ | |
mJavaObject = className != null ? CastTo(javaObject, className) : javaObject; | |
} | |
public AndroidJavaObject GetJavaObject() | |
{ | |
return mJavaObject; | |
} | |
// Same Java type is generics type, so we need static cast it from "java.lang.Object" to className | |
// TODO: need to handle Java Cast Exception | |
protected AndroidJavaObject CastTo(AndroidJavaObject javaObject, string className) | |
{ | |
using (AndroidJavaClass clazz = new AndroidJavaClass("java.lang.Class")) | |
{ | |
using (AndroidJavaObject destClass = clazz.CallStatic<AndroidJavaObject>("forName", className)) | |
{ | |
return destClass.Call<AndroidJavaObject>("cast", javaObject); | |
} | |
} | |
} | |
public void Dispose() | |
{ | |
if (mJavaObject != null) | |
{ | |
mJavaObject.Dispose(); | |
} | |
} | |
} | |
/** | |
* Wrapper for Java class: com.huawei.hms.network.file.download.api.GetRequest | |
* | |
* 下载请求实体类:用于设置下载请求相关参数。 | |
* @see https://developer.huawei.com/consumer/cn/doc/development/HMSCore-References-V5/network-file-download-getrequest-0000001077788932-V5 | |
* @see https://developer.huawei.com/consumer/cn/doc/development/HMSCore-References-V5/network-file-request-0000001077340598-V5 | |
*/ | |
public class GetRequest : AndroidJavaObjectWrapper | |
{ | |
public GetRequest(AndroidJavaObject javaObject) : base(javaObject, "com.huawei.hms.network.file.download.api.GetRequest") | |
{ | |
} | |
/** | |
* 获用请求地址。 | |
*/ | |
public string GetUrl() | |
{ | |
return mJavaObject.Call<string>("getUrl"); | |
} | |
/** | |
* 获取下载文件的本地保存路径。 | |
*/ | |
public string GetFilePath() | |
{ | |
return mJavaObject.Call<string>("getFilePath"); | |
} | |
/** | |
* 获取文件大小。 | |
*/ | |
public long GetFileSize() | |
{ | |
return mJavaObject.Call<long>("getFileSize"); | |
} | |
/** | |
*获取请求ID。 | |
*/ | |
public long GetId() | |
{ | |
return mJavaObject.Call<long>("getId"); | |
} | |
/** | |
*获取请求名称。 | |
*/ | |
public string GetName() | |
{ | |
return mJavaObject.Call<string>("getName"); | |
} | |
} | |
/** | |
* Wrapper for Java class: com.huawei.hms.network.file.api.Response<GetRequest, File, Closeable> | |
* | |
* 文件上传/下载请求结果的实体类。 | |
* @see https://developer.huawei.com/consumer/cn/doc/development/HMSCore-References-V5/network-file-response-0000001077788716-V5 | |
*/ | |
public class Response : AndroidJavaObjectWrapper | |
{ | |
public Response(AndroidJavaObject javaObject) : base(javaObject, "com.huawei.hms.network.file.api.Response") | |
{ | |
} | |
/** | |
* 获取请求结果响应码。 | |
*/ | |
public int GetCode() | |
{ | |
return mJavaObject.Call<int>("getCode"); | |
} | |
/** | |
* 获取响应的结果信息。 | |
*/ | |
public string GetMessage() | |
{ | |
return mJavaObject.Call<string>("getMessage"); | |
} | |
/** | |
* 获取请求结果内容。 | |
*/ | |
public FileInfo GetContent() | |
{ | |
using (AndroidJavaObject context = mJavaObject.Call<AndroidJavaObject>("getContent")) | |
{ | |
if (context != null) | |
{ | |
using (AndroidJavaObject file = CastTo(context, "java.io.File")) // cast `java.lang.Object` -> `java.io.File` | |
{ | |
return new FileInfo(file.Call<string>("getAbsolutePath")); // convert Java `java.io.File` -> C# `System.IO.FileInto` | |
} | |
} | |
} | |
return null; | |
} | |
} | |
/** | |
* Wrapper for Java class: com.huawei.hms.network.file.api.Progress | |
* | |
* 文件上传/下载任务执行过程相关信息实体类。 | |
* @see https://developer.huawei.com/consumer/cn/doc/development/HMSCore-References-V5/network-file-progress-0000001077469134-V5 | |
*/ | |
public class Progress : AndroidJavaObjectWrapper | |
{ | |
public Progress(AndroidJavaObject javaObject) : base(javaObject, "com.huawei.hms.network.file.api.Progress") | |
{ | |
} | |
/** | |
* 获取当前已上传/下载的文件大小,单位:Byte。 | |
*/ | |
public long GetFinishedSize() | |
{ | |
return mJavaObject.Call<long>("getFinishedSize"); | |
} | |
/** | |
* 获取当前请求进度,范围:[0, 100]。 | |
*/ | |
public int GetProgress() | |
{ | |
return mJavaObject.Call<int>("getProgress"); | |
} | |
/** | |
* 获取实时文件上传/下载的速度,单位:Byte/s。 | |
*/ | |
public long GetSpeed() | |
{ | |
return mJavaObject.Call<long>("getSpeed"); | |
} | |
/** | |
* 获取整个文件的大小,单位:Byte。 | |
*/ | |
public long GetTotalSize() | |
{ | |
return mJavaObject.Call<long>("getTotalSize"); | |
} | |
} | |
/** | |
* Wrapper for Java class: com.huawei.hms.network.file.api.exception.NetworkException | |
* | |
* 文件上传/下载异常基类。 | |
* @see https://developer.huawei.com/consumer/cn/doc/development/HMSCore-References-V5/network-file-exception-networkexception-0000001091598055-V5 | |
*/ | |
public class DownloadException : AndroidJavaObjectWrapper | |
{ | |
public DownloadException(AndroidJavaObject javaObject) : base(javaObject, "com.huawei.hms.network.file.api.exception.NetworkException") | |
{ | |
} | |
/** | |
* 获取错误信息 | |
*/ | |
public string GetMessage() | |
{ | |
return mJavaObject.Call<string>("getMessage"); | |
} | |
/** | |
* 打印错误堆栈(Java堆栈) | |
*/ | |
public void printStackTrace() | |
{ | |
mJavaObject.Call("printStackTrace"); | |
} | |
} | |
/** | |
* Wrapper for Java class: com.huawei.hms.network.file.api.Result | |
* | |
* 文件上传/下载相关操作(发起请求、取消请求、暂停下载、继续下载、销毁请求下载缓存和关闭线程池)返回的实体类。 | |
* @see https://developer.huawei.com/consumer/cn/doc/development/HMSCore-References-V5/network-file-result-0000001091587549-V5 | |
*/ | |
public class Result : AndroidJavaObjectWrapper | |
{ | |
/** | |
* 表示任务成功的常量。 | |
*/ | |
public static readonly int SUCCESS; | |
/** | |
* 表示任务暂停的常量。 | |
*/ | |
public static readonly int PAUSE; | |
/** | |
* 表示任务取消的常量 | |
*/ | |
public static readonly int CANCEL; | |
static Result() { | |
using (AndroidJavaClass resultClass = new AndroidJavaClass("com.huawei.hms.network.file.api.Result")) | |
{ | |
SUCCESS = resultClass.GetStatic<int>("SUCCESS"); | |
PAUSE = resultClass.GetStatic<int>("PAUSE"); | |
CANCEL = resultClass.GetStatic<int>("CANCEL"); | |
} | |
} | |
public Result(AndroidJavaObject javaObject) : base(javaObject) | |
{ | |
} | |
/** | |
* 获取请求操作的结果码。 | |
*/ | |
public int GetCode() | |
{ | |
return mJavaObject.Call<int>("getCode"); | |
} | |
/** | |
* 获取请求操作的结果信息。 | |
*/ | |
public string GetMessage() | |
{ | |
return mJavaObject.Call<string>("getMessage"); | |
} | |
} | |
/** | |
* HMS Network Kit Downloader Manager | |
* @see https://developer.huawei.com/consumer/cn/doc/development/HMSCore-Guides-V5/network-introduction-0000001050440045-V5 | |
* | |
* Java class: com.huawei.hms.network.file.download.api.DownloadManager | |
* 下载任务管理实体类。 | |
* @see https://developer.huawei.com/consumer/cn/doc/development/HMSCore-References-V5/network-file-download-downloadmanager-0000001077469352-V5 | |
*/ | |
public class HmsDownloadManager : IDisposable | |
{ | |
private static bool DEBUG = true; | |
private const string DOWNLOAD_MANAGER_NAME = "HmsDownloadManager"; | |
private const string CLASS_DOWNLOAD_MANAGER ="com.huawei.hms.network.file.download.api.DownloadManager"; | |
private const string CLASS_DOWNLOAD_MANAGER_BUILDER = "com.huawei.hms.network.file.download.api.DownloadManager$Builder"; | |
private const string CLASS_GET_REQUEST_BUILDER = "com.huawei.hms.network.file.download.api.GetRequest$Builder"; | |
private const string CLASS_CALLBACK = "com.huawei.hms.network.file.api.Callback"; | |
private AndroidJavaClass mDownloadManagerCls = null; | |
private AndroidJavaClass mDownloadManagerBuilderCls = null; | |
private AndroidJavaClass mGetRequestBuilderCls = null; | |
private AndroidJavaClass mCallbackCls = null; | |
private AndroidJavaObject mDownloadManager = null; | |
public HmsDownloadManager() | |
{ | |
mDownloadManagerCls = new AndroidJavaClass(CLASS_DOWNLOAD_MANAGER); | |
mDownloadManagerBuilderCls = new AndroidJavaClass(CLASS_DOWNLOAD_MANAGER_BUILDER); | |
mGetRequestBuilderCls = new AndroidJavaClass(CLASS_GET_REQUEST_BUILDER); | |
mCallbackCls = new AndroidJavaClass(CLASS_CALLBACK); | |
if (DEBUG) | |
{ | |
Debug.Log("[HmsDownloadManager] " + CLASS_DOWNLOAD_MANAGER + " " + mDownloadManagerCls); | |
Debug.Log("[HmsDownloadManager] " + CLASS_DOWNLOAD_MANAGER_BUILDER + " " + mDownloadManagerBuilderCls); | |
Debug.Log("[HmsDownloadManager] " + CLASS_GET_REQUEST_BUILDER + " " + mGetRequestBuilderCls); | |
Debug.Log("[HmsDownloadManager] " + CLASS_CALLBACK + " " + mCallbackCls); | |
} | |
// TODO: Java class not found will throw AndroidJavaException, how to handle this Java exception in Unity? | |
} | |
public void Dispose() | |
{ | |
if (mDownloadManagerCls != null) | |
{ | |
mDownloadManagerCls.Dispose(); | |
} | |
if (mDownloadManagerBuilderCls != null) | |
{ | |
mDownloadManagerBuilderCls.Dispose(); | |
} | |
if (mGetRequestBuilderCls != null) | |
{ | |
mGetRequestBuilderCls.Dispose(); | |
} | |
if (mCallbackCls != null) | |
{ | |
mCallbackCls.Dispose(); | |
} | |
if (mDownloadManager != null) | |
{ | |
mDownloadManager.Dispose(); | |
} | |
} | |
private bool EnsureDownloadManager() | |
{ | |
if (mDownloadManager == null) | |
{ | |
mDownloadManager = this.BuildDownloadManager(DOWNLOAD_MANAGER_NAME); | |
if (DEBUG) | |
{ | |
Debug.Log("[HmsDownloadManager] create new DownloadManager"); | |
} | |
} | |
return mDownloadManager != null; | |
} | |
/** | |
* Build a new DownloadManager | |
* | |
* Java code: | |
* <code> | |
* DownloadManager downloadManager = new DownloadManager.Builder(name).build(context); | |
* </code> | |
* | |
* @param name name | |
* @return DownloadManager(Java Object) | |
*/ | |
private AndroidJavaObject BuildDownloadManager(string name) | |
{ | |
using (AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) | |
{ | |
using (AndroidJavaObject context = jc.GetStatic<AndroidJavaObject>("currentActivity")) | |
{ | |
using (AndroidJavaObject builder = new AndroidJavaObject(CLASS_DOWNLOAD_MANAGER_BUILDER, name)) | |
{ | |
if (DEBUG) | |
{ | |
Debug.Log("DownloadManagerBuilder: " + builder); | |
} | |
return builder.Call<AndroidJavaObject>("build", context); | |
} | |
} | |
} | |
} | |
/** | |
* 构建一个GetRequest请求 | |
* | |
* Java code: | |
* <code> | |
* GetRequest getRequest = DownloadManager.newGetRequestBuilder() | |
* .filePath(downloadFilePath) | |
* .url(normalUrl) | |
* .build(); | |
* </code> | |
* | |
* @param url input url | |
* @param filepath output filepath | |
* @return GetRequest(Java Object) | |
*/ | |
public GetRequest NewGetRequest(string url, string filepath) | |
{ | |
using (AndroidJavaObject requestBuilder = new AndroidJavaObject(CLASS_GET_REQUEST_BUILDER)) | |
{ | |
requestBuilder.Call<AndroidJavaObject>("url", url); | |
requestBuilder.Call<AndroidJavaObject>("filePath", filepath); | |
return new GetRequest(requestBuilder.Call<AndroidJavaObject>("build")); | |
} | |
} | |
/** | |
* 发起一次异步的下载任务。 | |
* | |
* Java code: | |
* <code> | |
* Result result = downloadManager.start(getRequest, callback); | |
* </code> | |
* | |
* @param url input url | |
* @param filepath output filepath | |
* @param callback download callback | |
* @return Result or null | |
*/ | |
public Result Start(GetRequest request, FileRequestCallback callback) | |
{ | |
if (EnsureDownloadManager()) | |
{ | |
AndroidJavaObject javaResultObj = mDownloadManager.Call<AndroidJavaObject>("start", request.GetJavaObject(), new JavaFileRequestCallback(callback)); | |
Result result = new Result(javaResultObj); | |
if (DEBUG) | |
{ | |
Debug.Log("HmsDownloadManager.Start(), url=" + request.GetUrl() + ", filepath=" + request.GetFilePath() | |
+ ", result=" + (result != null ? result.GetCode() + " " + result.GetMessage() : "Fail")); | |
} | |
return result; | |
} | |
return null; | |
} | |
/** | |
* 暂停对应ID的任务。 | |
* | |
* Java code: | |
* <code> | |
* Result result = downloadManager.pauseRequest(requestId); | |
* </code> | |
* | |
* @param requestId requestId | |
* @return Result or null | |
*/ | |
public Result PauseRequest(long requestId) | |
{ | |
if (EnsureDownloadManager()) | |
{ | |
AndroidJavaObject javaResultObj = mDownloadManager.Call<AndroidJavaObject>("pauseRequest", requestId); | |
Result result = new Result(javaResultObj); | |
if (DEBUG) | |
{ | |
Debug.Log("HmsDownloadManager.PauseRequest(), requestId=" + requestId | |
+ ", result=" + (result != null ? result.GetCode() + " " + result.GetMessage() : "Fail")); | |
} | |
return result; | |
} | |
return null; | |
} | |
/** | |
* 继续对应下载请求的下载任务。 | |
* | |
* Java code: | |
* <code> | |
* Result result = downloadManager.resumeRequest(getRequest, callback); | |
* </code> | |
* | |
* @param url input url | |
* @param filepath output filepath | |
* @param callback download callback | |
* @return Result or null | |
*/ | |
public Result ResumeRequest(GetRequest request, FileRequestCallback callback) | |
{ | |
if (EnsureDownloadManager()) | |
{ | |
AndroidJavaObject javaResultObj = mDownloadManager.Call<AndroidJavaObject>("resumeRequest", request, new JavaFileRequestCallback(callback)); | |
Result result = new Result(javaResultObj); | |
if (DEBUG) | |
{ | |
Debug.Log("HmsDownloadManager.Start(), url=" + request.GetUrl() + ", filepath=" + request.GetFilePath() | |
+ ", result=" + (result != null ? result.GetCode() + " " + result.GetMessage() : "Fail")); | |
} | |
return result; | |
} | |
return null; | |
} | |
/** | |
* Java Callback for DownloadManager#start method | |
* com.huawei.hms.network.file.download.api.FileRequestCallback implements Callback<GetRequest, File> | |
* 它会直接将所有Java的Callback都直接回调给Unity的Callback | |
*/ | |
class JavaFileRequestCallback : AndroidJavaProxy | |
{ | |
private FileRequestCallback mUnityCallback; | |
public JavaFileRequestCallback(FileRequestCallback unityCallback) | |
: base(CLASS_CALLBACK) | |
{ | |
mUnityCallback = unityCallback; | |
} | |
AndroidJavaObject onStart(AndroidJavaObject request) | |
{ | |
using (var _request = new GetRequest(request)) | |
{ | |
mUnityCallback.OnStart(_request); | |
} | |
return request; // TODO: Java接口的onStart是返回request对象的,用于在onStart时修改request对象,Unity接口暂时未提供该功能 | |
} | |
void onProgress(AndroidJavaObject request, AndroidJavaObject progress) | |
{ | |
using (var _request = new GetRequest(request)) | |
{ | |
using (var _progress = new Progress(progress)) | |
{ | |
mUnityCallback.OnProgress(_request, _progress); | |
} | |
} | |
} | |
void onSuccess(AndroidJavaObject response) | |
{ | |
using (var _response = new Response(response)) | |
{ | |
mUnityCallback.OnSuccess(_response); | |
} | |
} | |
void onException(AndroidJavaObject request, AndroidJavaObject exception, AndroidJavaObject response) | |
{ | |
using (var _request = new GetRequest(request)) | |
{ | |
using (var _exception = new DownloadException(exception)) | |
{ | |
using (var _response = new Response(response)) | |
{ | |
mUnityCallback.OnException(_request, _exception, _response); | |
} | |
} | |
} | |
} | |
} | |
} // class HmsDownloadManager | |
} // namespace HmsNetworkKitUnofficial | |
#endif // UNITY_ANDROID |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Unity项目接入HmsNetworkKit说明
简介
Hms Network Kit是华为的一款网络基础服务套件,官方文档可参考 Network Kit指南 - 业务介绍。
因为Network Kit目前只提供Java的接口,官方暂时未提供Unity的插件或接口,因此本文档主要说明如何在Unity项目中接入Network Kit网络库。
接入SDK
修改Gradle
因为Hms Network Kit只提供gradle的方式接入,不提供jar包或者aar包,因此必须修改Unity的Gradle配置文件来接入。
Gradle的修改参考的是Hms Network Kit的官方文档:Network Kit指南 - 集成HMS Core SDK
Unity项目修改Gradle配置文件的方法是参考Unity的官方文档:Gradle for Android
这里综合上述两份官方文档,以Unity 2019.4.15f1为例,示范如何修改Gradle来接入华为的Hms Network Kit。
第一步:打开自定义Gradle模板文件
在Unity的菜单[Build] - [Build Settings]中选择Android平台,然后选择[Player Settings] - [Publishing Settings] 下勾选:
第二步:修改自定义Gradle模板文件
修改
Assets\Plugins\Android\baseProjectTemplate.gralde
配置文件,在allprojects - buildscript - repositories
和allprojects - repositories
节点下增加Hms的Gradle仓库:
修改
Assets\Plugins\Android\launcherTemplate.gradle
文件,在dependencies
节点下增加Hms Network Kit库的Gradle依赖:
修改AndroidManifest
Hms Network Kit按照官方文档Network Kit指南 - 添加权限, 需要在
AndroidManifest.xml
中增加如下权限,主要是:网络权限和读写SDCard权限。
调用API
因为Network Kit提供的都是Java API,因此需要通过Unity的
AndroidJavaObject
等API来调用。(注意这个Java API必须在Unity主线程或者Attach到JVM的子线程才能调用,否则会崩溃,具体可参考Unity官方文档AndroidJNI.AttachCurrentThread)大部分需要使用的Java API都封装成了Unity API,例如华为官方的Java调用方法可参考官网文档Network Kit指南 - 文件上传/下载 该示例中的Java代码转成Unity接口的调用方式示例如下:
回调函数如下: