Bootstrap

Lua小游戏别撞车——接入微信分享

本次的游戏代码是使用lua完成,所以接入第三方的SDK也和c++层的方法稍有区别,首先来说明整体的思路。我们是在Android应用平台接入的微信分享,所以在这个平台下,也就是java层实现接入逻辑,留下给c++层调用的接口,c++层通过jni来调用java层实现业务逻辑的接口,而我们是在Lua中完成的游戏逻辑,所以我们还需要做的一个步骤就是,将c++的接口导出给lua层来使用,这个过程需要使用lua-binding。

Lua小游戏别撞车——接入微信分享

前俩个过程我在博客用3.0实现飞机大战——接入微信分享有详细的说明,请大家参考这篇博客,我们把整个接入流程再走一遍。

1、将项目导入eclipse的工程中,添加微信的SDK,在微信的开发者中心申请接入的应用,获得APPID。

2、实现java层的接入逻辑,在AppActivity文件中实现了一些函数,应该是和lua有关的,不用管。在onCreate中调用注册代码,将用到的成员变量和接口函数写在appActivity文件中。以下是涉及到调用微信的代码,其中有一个Util类,在上面给的博客地址中有说明,注意包名写对了。

1 //微信SDK
2     private static final String APP_ID = "wx42ca6be8e52eebfb";
3     private static IWXAPI api;
4     private static AppActivity instance;
5  
6     static String hostIPAdress="0.0.0.0";
7     @Override
8     protected void onCreate(Bundle savedInstanceState) {
9         // TODO Auto-generated method stub
10         super.onCreate(savedInstanceState);
11  
12         //注册到微信
13         regToWX();
14  
15         if(nativeIsLandScape()) {
16             setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
17         else {
18             setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
19         }
20  
21         //2.Set the format of window
22  
23         // Check the wifi is opened when the native is debug.
24         if(nativeIsDebug())
25         {
26             getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
27             if(!isNetworkConnected())
28             {
29                 AlertDialog.Builder builder=new AlertDialog.Builder(this);
30                 builder.setTitle("Warning");
31                 builder.setMessage("Open Wifi for debuging...");
32                 builder.setPositiveButton("OK",new DialogInterface.OnClickListener() {
33  
34                     @Override
35                     public void onClick(DialogInterface dialog, int which) {
36                         startActivity(new Intent(Settings.ACTION_WIFI_SETTINGS));
37                         finish();
38                         System.exit(0);
39                     }
40                 });
41                 builder.setCancelable(false);
42                 builder.show();
43             }
44         }
45         hostIPAdress = getHostIpAddress();
46     }
47  
48     //初始化微信
49     private void regToWX(){
50         api = WXAPIFactory.createWXAPI(this, APP_ID, true);
51         api.registerApp(APP_ID);
52     }
53  
54     //留下给c++层调用的接口
55     public static void sendMsgToFriend(){
56         if(api.openWXApp())
57         {
58                 //初始化一个对象WebpageObject
59             WXTextObject textObject = new WXTextObject();
60             textObject.text = "小塔博客用lua写的小游戏别撞车,博客地址http://www.zaojiahua.com/tag/3-0%E9%A3%9E%E6%9C%BA%E5%A4%A7%E6%88%98!";
61  
62             //媒体对象中
63             WXMediaMessage msg = new WXMediaMessage(textObject);
64             msg.title = "别撞车";
65             msg.description = "分享给你的好友,让更多的人来玩!";
66  
67             //建立请求对象
68             SendMessageToWX.Req req = new SendMessageToWX.Req();
69             //transaction是用来表示一个请求的唯一标示符
70             req.transaction = buildTransaction("textObject");
71             req.message = msg;
72             req.scene = SendMessageToWX.Req.WXSceneSession;
73  
74             //使用通信类发送
75             api.sendReq(req);
76         }
77         else
78         {
79              Toast.makeText(instance, "启动微信失败!", Toast.LENGTH_SHORT).show();
80         }
81     }
82  
83     public static void sendMsgToTimeLine(){
84         if(api.openWXApp())
85         {
86             if(api.getWXAppSupportAPI() >= 0x21020001)
87             {
88                 WXWebpageObject webpage = new WXWebpageObject();
89                 webpage.webpageUrl = "http://m.baidu.com/app?action==content&docid=6561264&f=s1001";
90  
91                 WXMediaMessage msg = new WXMediaMessage(webpage);
92                 msg.title = "别撞车";
93                 msg.description = "分享到我的朋友圈,让更多的人来玩!";
94  
95                 Bitmap thumb = BitmapFactory.decodeResource(instance.getResources(),R.drawable.icon);
96                 msg.thumbData = Util.bmpToByteArray(thumb, true);
97  
98                 SendMessageToWX.Req req = new SendMessageToWX.Req();
99                 req.transaction = buildTransaction("webpage");
100                 req.message = msg;
101                 req.scene = SendMessageToWX.Req.WXSceneTimeline;
102                 api.sendReq(req);
103             }
104             else{
105                 Toast.makeText(instance, "微信版本过低", Toast.LENGTH_SHORT).show();
106             }
107         }
108         else
109         {
110              Toast.makeText(instance, "启动微信失败", Toast.LENGTH_SHORT).show();
111         }
112     }
113     private static String buildTransaction(final String type) {
114         return (type == null) ? String.valueOf(System.currentTimeMillis()) : type + System.currentTimeMillis();
115     }

Lua小游戏别撞车——接入微信分享

3、接下来实现c++层的逻辑,从这里开始才是本篇博客重点要说明的。首先需要打开c++层的代码,我是在Mac下写的代码,所以打开我的Xcode工程,工程位置如图所示,如果没有frameworks文件夹,可以采用如图的操作。

Lua小游戏别撞车——接入微信分享Lua小游戏别撞车——接入微信分享

之前我们写的圆周运动类是在classes文件夹下,注册是在appDelegate中完成的,这种方法在我的博客绑定自定义类到Runtime(Lua-binding)中有详细的说明,本篇博客采用另一种更加简单的方法,但是思路是不变的,采用这种方法以后扩展比较容易,再换一种方式来做可以更好的理解绑定的机制。

在frameworks/cocos2d-x/cocos目录下新建custom文件夹,顾名思义就是自定义的一些类,以后我们可以将自己定义的类全部放到这个文件夹中,在这个文件夹中新建类WeixinShare,然后在工程中导入这个类,导入路径如下。

Lua小游戏别撞车——接入微信分享Lua小游戏别撞车——接入微信分享

以下是俩个静态函数的实现。

1 #ifndef __ColorBlind__WeixinShare__
2 #define __ColorBlind__WeixinShare__
3  
4 #if(CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
5  
6 #include "platform/android/jni/JniHelper.h"
7 #include <jni.h>
8  
9 #endif
10  
11 #include "Cocos2d.h"
12 USING_NS_CC;
13  
14 class CC_DLL WeixinShare
15 {
16 public:
17     static void sendToFriend();
18     static void sendToTimeLine();
19 };
20  
21 #endif /* defined(__DontCrash__WeixinShare__) */
1 #include "WeixinShare.h"
2  
3 #if(CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
4  
5 #include "platform/android/jni/JniHelper.h"
6 #include <jni.h>
7  
8 #endif
9  
10 void WeixinShare::sendToFriend()
11 {
12 #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) //判断当前是否为Android平台
13     JniMethodInfo minfo;
14  
15     bool isHave = JniHelper::getStaticMethodInfo(minfo,"org/cocos2dx/lua/AppActivity","sendMsgToFriend""()V");
16  
17     if (!isHave) {
18         log("jni:sendMsgToFriend is null");
19     }else{
20         //调用此函数
21         minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID);
22     }
23 #endif
24 }
25  
26 void WeixinShare::sendToTimeLine()
27 {
28 #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) //判断当前是否为Android平台
29     JniMethodInfo minfo;
30  
31     bool isHave = JniHelper::getStaticMethodInfo(minfo,"org/cocos2dx/lua/AppActivity","sendMsgToTimeLine""()V");
32  
33     if (!isHave) {
34         log("jni:sendMsgToTimeLine is null");
35     }else{
36         //调用此函数
37         minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID);
38     }
39 #endif
40 }

这样的话c++层的代码也完成了,大家可以编译一下工程,看看是否有错误。如果没有错误我们就导出给lua使用。

4、进入tools/tolua目录,复制一份cocos2dx.ini配置文件,改名为cocos2dx_custom.ini文件,然后修改这个文件,主要注意的地方如图所示。

Lua小游戏别撞车——接入微信分享Lua小游戏别撞车——接入微信分享

这样我们自己导出类的配置文件就OK啦,然后打开genbinding.py文件,添加一行新的配置文件内容。

Lua小游戏别撞车——接入微信分享

接着在控制台下执行脚本genbinding.py。

Lua小游戏别撞车——接入微信分享Lua小游戏别撞车——接入微信分享

这样在auto目录下我们就成功的得到了桥接函数lua_cocos2dx_custom_auto,现在我们将这个桥接函数导入到我们的工程中,之所以要导入是为了让整个项目在编译的时候编译这些文件。在lua_cocos2dx_custom_auto.cpp中,对WeixinShare.h的包含要加入目录名。现在编译整个工程,如果编译成功代表导出的就没有问题,我们才能进行下一步。

Lua小游戏别撞车——接入微信分享Lua小游戏别撞车——接入微信分享

现在只差最后一步注册了,之前的函数注册是在appDelegate中完成的,这次的注册和cocos2d-x的注册函数放到一起完成,路径在cocos/scripting/lua-bindings/manual/CCLuaStack.cpp文件中,需要先包含头文件,所谓的注册就是调用桥接函数的头文件中所声明的那个函数。

Lua小游戏别撞车——接入微信分享Lua小游戏别撞车——接入微信分享

函数注册完毕以后我们需要重新编译一下c++层的代码,你可以在Xcode中编译,也可以在IDE中build一下runtime,俩者的道理是一样的,都是重新编译c++层代码。不过需要注意的是,如果是在Xcode工程中编译的代码,在IDE中可能需要选择一下使用最新编译出来的runtime,如图所示。整个lua-binding的过程就是这样,这么做的方便是以后如果你写很多的自定义类那么只需要在custom目录下新建文件,在init中新增自己的类名,然后运行genbinding.py脚本就会生成绑定的接口了,不再需要注册自己的多个导出函数了,刚才的这些步骤刚开始做是比较麻烦,不过为以后再导出自定义的类省下不少功夫。

Lua小游戏别撞车——接入微信分享

5、下面我们就使用导出的函数来完成程序的功能,先对lua层的代码稍作修改,添加调用分享的菜单项。

1 --游戏介绍以后的处理
2 function MainGameScene:gameOver(layer)
3     --清除数据
4     GlobalData:reset()
5     self.score:setString("0")
6     --重新设置小车的位置
7     self:resetCar()
8  
9     --添加分享和更多菜单项
10     self:addButton(layer)
11 end
12  
13 function MainGameScene:addButton(layer)
14     local share = cc.MenuItemImage:create("share.png","","")
15     share:setScale(0.8)
16     local more = cc.MenuItemImage:create("more.png","","")
17     more:setScale(0.8)
18     local retry = cc.MenuItemImage:create("retry.png","","")
19     retry:setScale(0.8)
20     local menu = cc.Menu:create(share,retry,more)
21     menu:alignItemsHorizontallyWithPadding(self.size.width*0.1)
22     menu:setPosition(cc.p(self.size.width/2,self.size.height/2))
23     layer:addChild(menu,3)
24  
25     --callback
26     local retry_callback = function()
27         --播放音效
28         SoundDeal:playEffect(EffectType.Start)
29         retry:runAction(cc.Sequence:create(cc.ScaleTo:create(0.05,1.3),
30             cc.CallFunc:create(function()menu:removeFromParentAndCleanup(trueend)))
31         self:runRedCar(self.car_red)
32         self:runYelloCar(self.car_yello)
33         self.play = true
34         self:collision(layer)
35     end
36     local share_callback = function()
37         share:runAction(cc.Sequence:create(cc.ScaleTo:create(0.05,1.3),cc.ScaleTo:create(0.05,0.8)))
38         if cc.Application:getInstance():getTargetPlatform() == cc.PLATFORM_OS_ANDROID then
39             cc.WeixinShare:sendToFriend()
40         end
41     end
42     local more_callback = function()
43         more:runAction(cc.Sequence:create(cc.ScaleTo:create(0.05,1.3),cc.ScaleTo:create(0.05,0.8)))
44     end
45     retry:registerScriptTapHandler(retry_callback)
46     share:registerScriptTapHandler(share_callback)
47     more:registerScriptTapHandler(more_callback)
48     --判断游戏是否开始的变量
49     self.play = false
50 end

通过cc.WeixinShare:sendToFriend()调用c++层导出来的接口,注意要判断一下平台。最后需要做的就是打包apk,来测试我们写的程序是否正确。在IDE中导出包的过程中,你可能会遇到类没有实现的错误,因为我们添加了自定义的类却没有告诉编译器啊,在之前我们把自定义的类添加到Xcode工程中就是告诉编译器要编译我们新建的类,现在的平台是Android,我们要怎么告诉编译器编译我们的类呢,那就是修改.mk文件。我们需要修改俩处文件,一个是将WeixinShare.cpp添加到.mk文件中,另一个是将导出的桥接函数lua_cocos2dx_custom_auto添加到.mk文件中,这俩个mk文件的位置如图所示。

Lua小游戏别撞车——接入微信分享Lua小游戏别撞车——接入微信分享Lua小游戏别撞车——接入微信分享Lua小游戏别撞车——接入微信分享

通过这几个步骤我们就完成了微信的分享功能,这个过程刚开始比较复杂,大家在完成了某一个阶段以后最好测试一下是否正确,出现错误仔细排查一下,只要认真一些一定可以导出成功的,最后微信分享的截图如下。

Lua小游戏别撞车——接入微信分享

;