本篇博客继续接入第三方SDK——接入微信分享。在接入微信分享之前,我们完善一下上篇博客的广告问题,当我从分数榜场景退出到开始场景的时候迷你广告还在上边,如果用户再进入一个关于作者的场景再玩游戏,上下俩个地方都会出现广告,也就是说广告在退出场景的时候并没有消失,我们需要做的就是解决这个问题。其实接入第三方SDK的原理很简单,以Android为例,在java层写接入代码,实现接入的逻辑,同时留下给c++层调用的接口,c++层通过jni来调用Android层的代码,整个接入SDK的逻辑就是这样。所以为了让广告消失,我们需要在Android层实现具体的逻辑,留下给c++层调用的接口,c++层必要的时候进行调用。
Android的具体实现逻辑如下,主要修改的是内部类AdHandler。
1 | class AdHandler extends Handler{ |
3 | private LinearLayout adBannerLayout= null ; |
4 | private LinearLayout adMiniLayout= null ; |
6 | public void handleMessage(Message msg) { |
10 | AppConnect.getInstance(mContext).showOffers(mContext); |
15 | boolean hasPopAd = AppConnect.getInstance(mContext).hasPopAd(mContext); |
17 | AppConnect.getInstance(mContext).showPopAd(mContext); |
22 | AppConnect.getInstance(mContext).showAppOffers(mContext); |
26 | AppConnect.getInstance(mContext).showGameOffers(mContext); |
33 | AdInfo adInfo = AppConnect.getInstance(mContext).getAdInfo(); |
34 | AppDetail.getInstanct().showAdDetail(mContext, adInfo); break ; |
37 | AppConnect.getInstance(mContext).spendPoints( 10 ,AppActivity. this ); |
41 | AppConnect.getInstance(mContext).awardPoints( 10 ,AppActivity. this ); |
45 | AppConnect.getInstance(mContext).showMore(mContext); |
49 | AppConnect.getInstance(mContext).showMore(mContext,app_id); |
53 | String uriStr = "http://www.baidu.com" ; AppConnect.getInstance(mContext).showBrowser(mContext,uriStr); |
57 | AppConnect.getInstance(mContext).showFeedback(mContext); |
61 | QuitPopAd.getInstance().show(mContext); |
65 | AppConnect.getInstance(mContext).showBannerAd(mContext,getBannerAd()); |
69 | AppConnect.getInstance(mContext).showMiniAd(mContext,getMiniAd(), 10 ); |
72 | this .uninstallAd(msg.what- 100 ); |
78 | private LinearLayout getBannerAd(){ |
80 | adBannerLayout = new LinearLayout(mContext); |
81 | adBannerLayout.setOrientation(LinearLayout.VERTICAL); |
82 | FrameLayout.LayoutParams lp_banner = new FrameLayout.LayoutParams( |
83 | FrameLayout.LayoutParams.FILL_PARENT, |
84 | FrameLayout.LayoutParams.WRAP_CONTENT); |
86 | lp_banner.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; |
87 | AppActivity. this .addContentView(adBannerLayout, lp_banner); |
89 | LinearLayout bannerLayout = new LinearLayout(mContext); |
90 | adBannerLayout.addView(bannerLayout); |
96 | private LinearLayout getMiniAd(){ |
97 | adMiniLayout = new LinearLayout(mContext); |
98 | adMiniLayout.setOrientation(LinearLayout.VERTICAL); |
99 | FrameLayout.LayoutParams lp_mini = new FrameLayout.LayoutParams( |
100 | FrameLayout.LayoutParams.FILL_PARENT, |
101 | FrameLayout.LayoutParams.WRAP_CONTENT); |
103 | lp_mini.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL; |
104 | AppActivity. this .addContentView(adMiniLayout, lp_mini); |
105 | LinearLayout miniLayout = new LinearLayout(mContext); |
106 | adMiniLayout.addView(miniLayout); |
112 | public void uninstallAd( int adTag){ |
114 | adBannerLayout.setVisibility(View.INVISIBLE); |
116 | else if (adTag == 14 ){ |
117 | adMiniLayout.setVisibility(View.INVISIBLE); |
留给c++层调用的接口如下:
2 | public static void uninstallAd( int adTag){ |
3 | Message msg = handler.obtainMessage(); |
6 | handler.sendMessage(msg); |
c++层使用jni来调用这个接口,代码如下:
1 | void WapsAd::uninstallAd( int adTag) |
3 | #if(CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) |
5 | bool isHave = JniHelper::getStaticMethodInfo(minfo, "org/cocos2dx/cpp/AppActivity" , "uninstallAd" , "(I)V" ); |
8 | CCLog( "jni:showAdStatic is null" ); |
13 | minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID,adTag); |
这样的话整个广告的代码就完善了,接下来接入微信SDK。
1、首先是准备工作,到官网上注册账号,下载SDK,将下载的jar包放到项目的libs目录下,主要步骤的截图如下。现在如果注册的是游戏会让你到腾讯开放平台注册,还要注册提交审核,我的第一次提交就失败了,所以我把描述信息给改了,让他看不出我是游戏还是应用,为了让你的应用在使用分享功能的时候是正常的,第一注意包名,就是你要上线游戏的包名,还有一个是应用签名,你需要下载微信获取签名的一个工具,使用这个工具来获取你安装包的签名,所以打包的时候就打一个release包吧,安装到手机上,然后使用微信提供的工具去获取签名,工具的下载地址。然后就等待审核了,工作日的话半天就OK了,不是很严格。
2、接下来我们使用刚才上边提到的思路来写代码,先完成java层的代码,将接口函数留给c++层调用。注意APP_ID是从微信后台获取的,然后在onCreate函数中初始化一下连接微信的代码。
2 | private static final String APP_ID = "wx42ca6be8e52eebfb" ; |
3 | private static IWXAPI api; |
4 | private static AppActivity instance; |
6 | protected void onCreate(Bundle savedInstanceState) { |
8 | super .onCreate(savedInstanceState); |
12 | handler = new AdHandler(); |
20 | private void regToWX(){ |
21 | api = WXAPIFactory.createWXAPI( this , APP_ID, true ); |
22 | api.registerApp(APP_ID); |
3、下面把接口留给c++层调用。调用微信API代码的逻辑是首先生成需要发送的消息对象,然后将消息对象附加到媒体对象中,接着建立请求对象,最后使用通信类发送即可。代码中还用到一个Util类,这个类我们需要在包下新建一个,代码是参考别人的,大家就当工具来用就可以了。消息对象有很多种,包括文本,音乐,视频等等,我们需要根据自己的需要创建不同的消息对象,这些消息对象的类名可以参考官方的文档。
1 | public static void sendMsgToFriend(){ |
5 | WXTextObject textObject = new WXTextObject(); |
9 | WXMediaMessage msg = new WXMediaMessage(textObject); |
11 | msg.description = "分享给你的好友,让更多的人来玩!" ; |
14 | SendMessageToWX.Req req = new SendMessageToWX.Req(); |
16 | req.transaction = buildTransaction( "textObject" ); |
18 | req.scene = SendMessageToWX.Req.WXSceneSession; |
25 | Toast.makeText(instance, "启动微信失败!" , Toast.LENGTH_SHORT).show(); |
29 | public static void sendMsgToTimeLine(){ |
32 | if (api.getWXAppSupportAPI() >= 0x21020001 ) |
34 | WXWebpageObject webpage = new WXWebpageObject(); |
37 | WXMediaMessage msg = new WXMediaMessage(webpage); |
39 | msg.description = "分享到我的朋友圈,让更多的人来玩!" ; |
41 | Bitmap thumb = BitmapFactory.decodeResource(instance.getResources(), com.zaojiahua.plane.R.drawable.icon); |
42 | msg.thumbData = Util.bmpToByteArray(thumb, true ); |
44 | SendMessageToWX.Req req = new SendMessageToWX.Req(); |
45 | req.transaction = buildTransaction( "webpage" ); |
47 | req.scene = SendMessageToWX.Req.WXSceneTimeline; |
51 | Toast.makeText(instance, "微信版本过低" , Toast.LENGTH_SHORT).show(); |
56 | Toast.makeText(instance, "启动微信失败" , Toast.LENGTH_SHORT).show(); |
59 | private static String buildTransaction( final String type) { |
60 | return (type == null ) ? String.valueOf(System.currentTimeMillis()) : type + System.currentTimeMillis(); |
1 | package org.cocos2dx.cpp; |
3 | import java.io.ByteArrayOutputStream; |
5 | import java.io.IOException; |
6 | import java.io.InputStream; |
7 | import java.io.RandomAccessFile; |
8 | import java.net.HttpURLConnection; |
9 | import java.net.MalformedURLException; |
11 | import java.net.URLConnection; |
13 | import junit.framework.Assert; |
15 | import android.graphics.Bitmap; |
16 | import android.graphics.BitmapFactory; |
17 | import android.graphics.Bitmap.CompressFormat; |
18 | import android.util.Log; |
22 | private static final String TAG = "SDK_Sample.Util" ; |
24 | public static byte [] bmpToByteArray( final Bitmap bmp, final boolean needRecycle) { |
25 | ByteArrayOutputStream output = new ByteArrayOutputStream(); |
26 | bmp.compress(CompressFormat.PNG, 100 , output); |
31 | byte [] result = output.toByteArray(); |
34 | } catch (Exception e) { |
41 | public static byte [] getHtmlByteArray( final String url) { |
43 | InputStream inStream = null ; |
45 | htmlUrl = new URL(url); |
46 | URLConnection connection = htmlUrl.openConnection(); |
47 | HttpURLConnection httpConnection = (HttpURLConnection)connection; |
48 | int responseCode = httpConnection.getResponseCode(); |
49 | if (responseCode == HttpURLConnection.HTTP_OK){ |
50 | inStream = httpConnection.getInputStream(); |
52 | } catch (MalformedURLException e) { |
54 | } catch (IOException e) { |
57 | byte [] data = inputStreamToByte(inStream); |
62 | public static byte [] inputStreamToByte(InputStream is) { |
64 | ByteArrayOutputStream bytestream = new ByteArrayOutputStream(); |
66 | while ((ch = is.read()) != - 1 ) { |
69 | byte imgdata[] = bytestream.toByteArray(); |
79 | public static byte [] readFromFile(String fileName, int offset, int len) { |
80 | if (fileName == null ) { |
84 | File file = new File(fileName); |
86 | Log.i(TAG, "readFromFile: file not found" ); |
91 | len = ( int ) file.length(); |
94 | Log.d(TAG, "readFromFile : offset = " + offset + " len = " + len + " offset + len = " + (offset + len)); |
97 | Log.e(TAG, "readFromFile invalid offset:" + offset); |
101 | Log.e(TAG, "readFromFile invalid len:" + len); |
104 | if (offset + len > ( int ) file.length()){ |
105 | Log.e(TAG, "readFromFile invalid file len:" + file.length()); |
111 | RandomAccessFile in = new RandomAccessFile(fileName, "r" ); |
117 | } catch (Exception e) { |
118 | Log.e(TAG, "readFromFile : errMsg = " + e.getMessage()); |
124 | private static final int MAX_DECODE_PICTURE_SIZE = 1920 * 1440 ; |
125 | public static Bitmap extractThumbNail( final String path, final int height, final int width, final boolean crop) { |
126 | Assert.assertTrue(path != null && !path.equals( "" ) && height > 0 && width > 0 ); |
128 | BitmapFactory.Options options = new BitmapFactory.Options(); |
131 | options.inJustDecodeBounds = true ; |
132 | Bitmap tmp = BitmapFactory.decodeFile(path, options); |
138 | Log.d(TAG, "extractThumbNail: round=" + width + "x" + height + ", crop=" + crop); |
139 | final double beY = options.outHeight * 1.0 / height; |
140 | final double beX = options.outWidth * 1.0 / width; |
141 | Log.d(TAG, "extractThumbNail: extract beX = " + beX + ", beY = " + beY); |
142 | options.inSampleSize = ( int ) (crop ? (beY > beX ? beX : beY) : (beY < beX ? beX : beY)); |
143 | if (options.inSampleSize <= 1 ) { |
144 | options.inSampleSize = 1 ; |
148 | while (options.outHeight * options.outWidth / options.inSampleSize > MAX_DECODE_PICTURE_SIZE) { |
149 | options.inSampleSize++; |
152 | int newHeight = height; |
153 | int newWidth = width; |
156 | newHeight = ( int ) (newWidth * 1.0 * options.outHeight / options.outWidth); |
158 | newWidth = ( int ) (newHeight * 1.0 * options.outWidth / options.outHeight); |
162 | newHeight = ( int ) (newWidth * 1.0 * options.outHeight / options.outWidth); |
164 | newWidth = ( int ) (newHeight * 1.0 * options.outWidth / options.outHeight); |
168 | options.inJustDecodeBounds = false ; |
170 | Log.i(TAG, "bitmap required size=" + newWidth + "x" + newHeight + ", orig=" + options.outWidth + "x" + options.outHeight + ", sample=" + options.inSampleSize); |
171 | Bitmap bm = BitmapFactory.decodeFile(path, options); |
173 | Log.e(TAG, "bitmap decode failed" ); |
177 | Log.i(TAG, "bitmap decoded size=" + bm.getWidth() + "x" + bm.getHeight()); |
178 | final Bitmap scale = Bitmap.createScaledBitmap(bm, newWidth, newHeight, true ); |
185 | final Bitmap cropped = Bitmap.createBitmap(bm, (bm.getWidth() - width) >> 1 , (bm.getHeight() - height) >> 1 , width, height); |
186 | if (cropped == null ) { |
192 | Log.i(TAG, "bitmap croped size=" + bm.getWidth() + "x" + bm.getHeight()); |
196 | } catch ( final OutOfMemoryError e) { |
197 | Log.e(TAG, "decode bitmap failed: " + e.getMessage()); |
4、下面来写c++层的代码,大家可以参考上篇博客介绍的jni调用来完成微信分享接口的调用,我新建了一个WeixinShare类,专门来进行分享,代码如下。
7 | void WapsAd::showAd( int adTag) |
11 | #if(CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) |
13 | bool isHave = JniHelper::getStaticMethodInfo(minfo, "org/cocos2dx/cpp/AppActivity" , "showAdStatic" , "(I)V" ); |
16 | CCLog( "jni:showAdStatic is null" ); |
21 | minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID,adTag); |
26 | void WapsAd::uninstallAd( int adTag) |
28 | #if(CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) |
30 | bool isHave = JniHelper::getStaticMethodInfo(minfo, "org/cocos2dx/cpp/AppActivity" , "uninstallAd" , "(I)V" ); |
33 | CCLog( "jni:showAdStatic is null" ); |
38 | minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID,adTag); |
最后在合适的地方调用我们的分享接口就好了,这样的话整个Demo就完成的差不多了,下一步我们要做的就是上各个应用平台了,期待好运吧!