系统环境
本文所涉及到的系统及开发环境 :
操作系统版本: MacOS Catalina 10.15.6 手机Android版本: 9(MIUI 11.0.7) Unity版本: 2019.4.9f1 Android Studio版本: 3.6 微信版本: 7.0.19 微信开放平台SDK版本: 6.6.4
大概思路
微信开放平台提供的SDK有关于Android的,但是没有关于Unity的,所以要想通过Unity实现微信分享,只需要解决Unity和Android的通信问题,剩下的就是根据微信的官方文档实现微信分享文字、图片、链接、小程序等。
微信开放平台创建应用时 关于签名的问题
MD5签名是根据你开发Unity项目时所使用的keystore生成的,keystore文件所在的位置可以通过Unity->Player Settings -> Player -> Publishing Settings 的Keystore Manager找到。
找到keystore文件之后,之后就是生成签名,生成签名的方法可以用微信开发平台提供的签名生成工具,这种方法略显复杂,其实可以直接使用keytool查看对应的MD5签名。
以MacOS上Android Studio默认的debug.keystore为例,在debug.keystore的文件目录下输入:
keytool -list -v -keystore debug.keystore
结果如下图所示,蓝色框框住的内容就是对应的MD5签名,填写到微信开放平台是注意去掉所有的冒号
一、创建Android Library
这个时候你应该能看到新创建的Module了
二、将Unity Library和微信的openSDK拷贝到项目中
1. 将Unity Library拷贝到项目中
如果你仅仅是想建立从Unity到Android的单向连接,也就是Unity可以访问Android,而不需要Android访问Unity,那么可以跳过这一步。
如果是你想建立Unity到Android的双向通信,那么就需要访问UnityPlayer Java 项目了。 在Unity安装目录下找到 classes.jar 如果Unity编译用的Scripting Backend是Mono就是:
(...\Unity\Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono\Release\Classes\classes.jar)
如果是IL2CPP, 对应的目录就是
(...\Unity\Editor\Data\PlaybackEngines\AndroidPlayer\Variations\il2cpp\Release\Classes\classes.jar)
把classes.jar复制粘贴到前面创建的wechatshare moudle的libs文件夹下,最好重名下,比如unityplayer.jar
2. 将微信的openSDK拷贝到项目中
因为最终build出来的插件是放在Unity中使用 ,而不是Android Studio, 所以事实上它并不能够下载远程文件,所以我们需要将微信openSDK对应的jar文件下载下来。
下载地址:微信openSDK
这里笔者下载的6.6.4版本
和unityplayer.jar一样,将它放置在module的libs目录下
现在我们已经将unityplayer.jar和微信openSDK相关的jar加入到项目中了,现在我们要让Android Studio知道这件事。
三、设置Gradle File
对应wechatshare的build.gradle现在应该是长这样:
接下来把Dependencies的内容整个换成:
dependencies ``**{**``** **
compileOnly files (``**'libs/unityplayer.jar'**``)
implementation files (``**'libs/wechat-sdk-android-without-mta-6.6.4.jar'**``)
**}**
注意
**unityplayer.jar**使用的不是implementation files,而是compileOnly files,这样就可以 保证unityplayer.jar不会打包进入最终的Plugin文件中,从而避免和Unity项目中的classes.jar冲突。- 不要使用
implementation fileTree(dir: 'libs', include: ['*.jar']),这样写的话又会将unityplayer.jar编译进最终的plugin中造成libarary冲突
上面替换dependencies的步骤可能删除了单元测试的libraries, 检查你的项目文件目录并删除所有和测试相关的classes, 否则后面编译是没法通过的。
四、代码部分-实现Unity和Android的相互通信
先创建一个空的Activity
我们让MainAcitivy继承Activity
MainAcitivy的onCreate,事实上在通过Unity调用MainActivity里面的方法onCreate并不会被调用,因为第一次接触Android,所以具体并不清楚,所以不要尝试在这里面做一些初始化的信息。如果有Android大神欢迎指教关于onCreate没有被调用的原因。
根据微信官方文档的示例,要使你的程序启动后微信终端能响应你的程序,必须在代码中向微信终端注册你的 id,关键的两行代码:
// 通过WXAPIFactory工厂,获取IWXAPI的实例
api = WXAPIFactory.createWXAPI(this, APP_ID, true);
// 将应用的appId注册到微信
api.registerApp(APP_ID);
其中createWXAPI方法中的第一个参数是一个Context, 前面说了因为onCreate不会被调用,所以也就意味着MainActivity这个Activity其实是空的,即便笔者尝试过为MainActivity生成一个Instance传入createWXAPI中 ,依旧告知为空,当初笔者为这个抓破脑袋,实在是没做过Android开发.
后来网上寻寻觅觅,发现可以利用反射机制获取当前UnityPlayer的Activity,并得到当前的context具体代码如下:
public static Activity unityActivity;
private static Context context;
// 利用反射机制获取unity项目的上下文
static Context getContent(){
if(null == unityActivity) {
try {
Class<?> classtype = Class.forName("com.unity3d.player.UnityPlayer");
Activity activity = (Activity) classtype.getDeclaredField("currentActivity").get(classtype);
unityActivity = activity;
context = activity;
} catch (ClassNotFoundException e) {
System.out.println(e.getMessage());
} catch (IllegalAccessException e) {
System.out.println(e.getMessage());
} catch (NoSuchFieldException e) {
System.out.println(e.getMessage());
}
}
return context;
}
好了,这个关键问题解决了,剩下的就简单了,接下来就是在MainActivity中写下一系列public static方法,共Unity调用,一个简单的示例:
// 安卓调用Unity的方法示例
public static void SendMessageToUnity(String gameObjectName, String UnityMethodName){
// 第一个参数:Unity中某个GameObject的gameObjectName
// 第二个参数:挂在gameObjectName上的脚本的某个方法
// 第三个参数:UnityMethodName这个方法接受的参数,这里是个String
UnityPlayer.UnitySendMessage(gameObjectName, UnityMethodName, "Android发来的贺电");
}
在Unity中调用
public Text messageText = null;
private string _className = "com.unityplugins.wechatshare.MainActivity";
void Start() {
AndroidJavaClass mainActivityClass = new AndroidJavaClass(_className);
// 第一个参数: MainActivity中的方法名,即SendMessageToUnity,该方法没有返回值
// 第二、三个参数: 分别是SendMessageToUnity需要接收的第一和第二个参数,对比上面Java的代码
mainActivityClass.CallStatic("SendMessageToUnity", gameObject.name, "ReceiveFromAndroid");
}
private void ReceiveFromAndroid(string message) {
messageText.text = message;
}
完事之后可以进行个简单的测试,具体的编译流程:编译流程
如果都没有问题的话,运行成功后messageText对应的Text文本的内容会显示:Android发来的贺电
五、代码部分 - Android端微信分享相关代码
新建一个Java Class
笔者这里将之命名为WeChatController
在这个类里实现微信分享有关的各个功能:向微信注册APP、分享场景(朋友圈、对话、收藏)、分享各类媒体内容等。具体请参考微信官方文档,这里不一一讲解,部分代码如下:
public class WeChatController {
public static IWXAPI api;
private String _APP_ID = "";
private static WeChatController Instance = null;
public static WeChatController GetInstance() {
if (Instance == null) {
Instance = new WeChatController();
}
return Instance;
}
public void Init(Context content, String APP_ID) {
_APP_ID = APP_ID;
RegisterAppToWX(content);
}
private void RegisterAppToWX(Context content) {
api = WXAPIFactory.createWXAPI(content, _APP_ID, true);
api.registerApp(_APP_ID);
}
// 判断是否安装了微信
public boolean IsWeChatInstalled() {
return api.isWXAppInstalled();
}
// 分享链接至微信
// scene: 分享到哪个场景 0 代表对话、1 代表朋友圈、2 代码收藏
public void ShareWebpageToWX(int scene, String url, String title, String description) {
// 设置网址
WXWebpageObject webpageObject = new WXWebpageObject();
webpageObject.webpageUrl = url;
// 设置标题
WXMediaMessage msg = new WXMediaMessage(webpageObject);
msg.title = title;
msg.description = description;
// 设置缩略图
msg.thumbData = GetDrawableIconByPackageName(MainActivity.PackageName);
// 构造一个发信请求
SendMessageToWX.Req req = new SendMessageToWX.Req();
req.transaction = BuildTransaction("webpage");
req.message = msg;
req.scene = scene;
// 发送请求给微信客户端
api.sendReq(req);
}
// 分享文字至微信
public void ShareTextToWX(int scene, String text) {
//初始化一个 WXTextObject 对象,填写分享的文本内容
WXTextObject textObj = new WXTextObject();
textObj.text = text;
//用 WXTextObject 对象初始化一个 WXMediaMessage 对象
WXMediaMessage msg = new WXMediaMessage();
msg.mediaObject = textObj;
msg.description = text;
SendMessageToWX.Req req = new SendMessageToWX.Req();
req.transaction = BuildTransaction("text");
req.message = msg;
req.scene = scene;
//调用api接口,发送数据到微信
api.sendReq(req);
}
// 分享图片至微信
public void ShareImageToWX(int scene, byte[] imgData) {
WXImageObject imgObj = new WXImageObject(imgData);
WXMediaMessage msg = new WXMediaMessage();
msg.mediaObject = imgObj;
msg.thumbData = GetDrawableIconByPackageName(MainActivity.PackageName);
SendMessageToWX.Req req = new SendMessageToWX.Req();
req.transaction = BuildTransaction("img");
req.message = msg;
req.scene = scene;
api.sendReq(req);
}
// 分享音乐至微信
public void ShareMusicToWX(int scene, String musicUrl, String title, String description){
//初始化一个WXMusicObject,填写url
WXMusicObject music = new WXMusicObject();
music.musicUrl= musicUrl;
//用 WXMusicObject 对象初始化一个 WXMediaMessage 对象
WXMediaMessage msg = new WXMediaMessage();
msg.mediaObject = music;
msg.title = title;
msg.description = description;
msg.thumbData = GetDrawableIconByPackageName(MainActivity.PackageName);
//构造一个Req
SendMessageToWX.Req req = new SendMessageToWX.Req();
req.transaction = BuildTransaction("music");
req.message = msg;
req.scene = scene;
//调用api接口,发送数据到微信
api.sendReq(req);
}
// 分享视频至微信
public void ShareVideoToWX(int scene, String videoUrl, String title, String description){
//初始化一个WXVideoObject,填写url
WXVideoObject video = new WXVideoObject();
video.videoUrl =videoUrl;
//用 WXVideoObject 对象初始化一个 WXMediaMessage 对象
WXMediaMessage msg = new WXMediaMessage(video);
msg.title = title;
msg.description = description;
msg.thumbData = GetDrawableIconByPackageName(MainActivity.PackageName);
//构造一个Req
SendMessageToWX.Req req = new SendMessageToWX.Req();
req.transaction = BuildTransaction("video");
req.message =msg;
req.scene = scene;
//调用api接口,发送数据到微信
api.sendReq(req);
}
// 分享小程序至微信
public void ShareMinniProgramToWX(int scene, String lowVersionUrl, String miniProgramAPPID, String path,
String title, String description, byte[] coverImgData){
WXMiniProgramObject miniProgramObj = new WXMiniProgramObject();
miniProgramObj.webpageUrl = lowVersionUrl; // 兼容低版本的网页链接
miniProgramObj.miniprogramType = WXMiniProgramObject.MINIPTOGRAM_TYPE_RELEASE;// 正式版:0,测试版:1,体验版:2
miniProgramObj.userName = miniProgramAPPID; // 小程序原始id
miniProgramObj.path = path; //小程序页面路径;对于小游戏,可以只传入 query 部分,来实现传参效果,如:传入 "?foo=bar"
WXMediaMessage msg = new WXMediaMessage(miniProgramObj);
msg.title = title; // 小程序消息title
msg.description = description; // 小程序消息desc
msg.thumbData = coverImgData; // 小程序消息封面图片,小于128k
SendMessageToWX.Req req = new SendMessageToWX.Req();
req.transaction = BuildTransaction("miniProgram");
req.message = msg;
req.scene = scene;
api.sendReq(req);
}
private String BuildTransaction(final String type) {
return (type == null) ? String.valueOf(System.currentTimeMillis()) : type + System.currentTimeMillis();
}
}
六、编译流程
Android Studio部分
Android Studio右上角有个“Gradle”, 点开然后找到 wechatshare/Tasks/build, 然后三连,即先后进行三步操作,clean -> build -> assemble, 如下图
生成的arr文件在 wechatshare/build/outputs/arr这个目录下
Unity部分
将Android Studio生成的aar文件拷贝到Unity中 Assets/Plugins/Android目录下(此目录默认是没有的,需要自己手动创建)
因为笔者用的Unity Library即unityplayer.jar是il2cpp目录下的,所以需要在Player Settings中将Scripting Backend设为 IL2CPP:
至此Unity的设置就完成了,接下来只需要Build And Run即可。
七、完整源码
github: github.com/JookiTsui/U… gitee: gitee.com/jooki/Unity…