欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Cocos2d-x 3.0中集成社交分享ShareSDK的详细步骤和常见问题解决

程序员文章站 2023-08-29 22:25:09
给自己的手机游戏增加些社交分享功能,有助于游戏宣传和提升知名度,是一种不错的社交营销手段。国内这方面的第三方插件有不少,比如sharesdk、友 盟分享组件、baidu分享...

给自己的手机游戏增加些社交分享功能,有助于游戏宣传和提升知名度,是一种不错的社交营销手段。国内这方面的第三方插件有不少,比如sharesdk、友 盟分享组件、baidu分享组件等,之前在研究2.2.2版本时,集成了sharesdk这个组件,这次迁移到cocos2d-x 3.0rc2依旧选择集成sharesdk,这里就来说说集成的过程,遇到的一些问题以及解决方法。这里仅以android平台游戏集成为例。


一、功能描述、sdk版本和帐号准备

功能大致是这样的:在游戏中设置一个按钮,点击这个按钮,弹出知名社交平台的分享图标集窗口,用户选择分享目标后,相关信息分享到对应的社交平台。分享结果通知通过toast显示在屏幕的下方。

这次依旧使用sharesdk for android 2.3.7版本(sharesdk-android-2.3.7),cocos2d-x的版本为3.0rc2。

集成前,你需要有一个基于cocos2d-x 3.0rc2的可运行的android平台游戏project,我们的集成就基于该project,这里我们的project名为gamedemo,gamedemo的源码结构大致是:

复制代码 代码如下:

gamedemo/
    – classes/
    – proj.android/
    – resources/
    – cocos2d/
    – cmakelists.txt
    – … …

使用sharesdk前,你需要在各大主流社交平台(微信、微博)申请开发者帐号以及游戏接入权限(app_key、app_secret)等,当然在sharesdk站点也应该有自己的帐号和应用appkey,这些申请的审核需要几个工作日,甚至更长。

二、sharesdk集成步骤

按照sharesdk官方manual说法,cocos2d-x集成sharesdk有三种方式,之前在cocos2d-x 2.2.2引擎中采用的是专用组件集成的方式,该组件(c2dxsharesdksample)可以在这里下载(https://github.com/sharesdkplatform/c2dxsharesdksample,该组件近期已经fix了我之前发现的bug)。

1.jar包集成

这次我们主要做微博、微信的社交分享,因此只需要微博、微信相关jar包。在c2dxsharesdksample/proj.android/libs下,我们找到以下几个jar包:

复制代码 代码如下:

  -rw-rw-r– 1 tonybai tonybai  97k  4月  8 18:10 mframework.jar
  -rw-rw-r– 1 tonybai tonybai 112k  4月  8 17:39 sharesdk-core-2.3.7.jar
  -rw-rw-r– 1 tonybai tonybai  19k  4月  8 17:39 sharesdk-sinaweibo-2.3.7.jar
  -rw-rw-r– 1 tonybai tonybai 4.3k  4月  8 17:39 sharesdk-wechat-2.3.7.jar
  -rw-rw-r– 1 tonybai tonybai  29k  4月  8 17:39 sharesdk-wechat-core-2.3.7.jar
  -rw-rw-r– 1 tonybai tonybai 4.6k  4月  8 17:39 sharesdk-wechat-favorite-2.3.7.jar
  -rw-rw-r– 1 tonybai tonybai 4.4k  4月  8 17:39 sharesdk-wechat-moments-2.3.7.jar

把这些jar包文件copy到gamedemo/proj.android/libs下。

2. 配置文件与资源部分集成

修改gamedemo/proj.android/androidmanifest.xml文件,在application标签下,添加如下activity标签:

复制代码 代码如下:

        <activity
            android:name="cn.sharesdk.framework.sharesdkuishell"
            android:configchanges="keyboardhidden|orientation|screensize"
            android:screenorientation="portrait"
            android:theme="@android:style/theme.translucent.notitlebar"
            android:windowsoftinputmode="statehidden|adjustresize" >
    </activity>
    <activity
            android:name=".wxapi.wxentryactivity"
            android:configchanges="keyboardhidden|orientation|screensize"
            android:exported="true"
            android:screenorientation="portrait"
            android:theme="@android:style/theme.translucent.notitlebar" />

将c2dxsharesdksample/proj.android/res下的如下目录中的文件复制到gamedemo/proj.android/res下:

复制代码 代码如下:

   drawable-hdpi/  drawable-ldpi/  drawable-mdpi/
   drawable-xhdpi/  layout/  values/  values-en/

注意,类似icon.png这种文件就不要复制了,自己做一下判断就好。

3. c++部分代码集成

将c2dxsharesdksample/classes下的c2dxsharesdk文件夹copy到gamedemo/classes下面。

由于cocos2d-x 3.0rc2的类命名发生了变化,我们需要对c2dxsharesdk中使用到的引擎中的类名以及方法名进行修改。但实际上cocos2d-x 3.0rc2考虑到了一些兼容性的问题,大部分名字通过cocos2d/cocos/deprecated/ccdeprecated.h中定义的typedef得以保留,虽然这些名字已经被建议deprecated了。rc2中ccobject被改名为ref了,这个我们需要手工在c2dxsharesdk进行修改。

另外sharesdk组件在实现时大量使用了ccdictionary、ccarray和ccstring,而这三个类在cocos2d-x 3.0rc2中均被deprecated了,但我们依然可以使用,所以我们可以不做修改。但以后随着cocos2d-x版本的演进,这些类很可能被彻底移除出引擎,我们就需要重新使用其替代品进行实现了。

此外我们还需要手工修改一下c2dxsharesdk/android/json/ccjsonconverter.cpp文件中的getobjjson方 法,因为rc2中ccdictionary、ccstring、ccarray这些类的真实名称都已经换成了__dictionary、__string 和__array,ccdictionary、ccstring、ccarray只是些typedef,因此要像下面这样做些修改(如果你是集成 cocos2d-x 2.x.x版本,则无需做下面修改):

复制代码 代码如下:

cjson * ccjsonconverter::getobjjson(ref * obj)
{
    std::string s = typeid(*obj).name();
    if(s.find("__dictionary")!=std::string::npos){
        cjson * json = cjson_createobject();
        convertdictionarytojson((ccdictionary *)obj, json);
        return json;
    }else if(s.find("__array")!=std::string::npos){
        cjson * json = cjson_createarray();
        convertarraytojson((ccarray *)obj, json);
        return json;
    }else if(s.find("__string")!=std::string::npos){
        ccstring * s = (ccstring *)obj;
        cjson * json = cjson_createstring(s->getcstring());
        return json;
    }else if(s.find("ccnumber")!=std::string::npos){
        ccnumber * n = (ccnumber *)obj;
        cjson * json = cjson_createnumber(n->getdoublevalue());
        return json;
    }else if(s.find("ccnull")!=std::string::npos){
        cjson * json = cjson_createnull();
        return json;
    }
    cclog("ccjsonconverter encountered an unrecognized type");
    return null;
}

ccnumber和ccnull是sharesdk组件自己实现的类名,这里无需修改。

接下来我们需要在appdelegate.cpp中对sharesdk做初始化了:

复制代码 代码如下:

bool appdelegate::applicationdidfinishlaunching() {
    … …
    initsharesdk();
    … ..
}

void appdelegate::initsharesdk()
{
    // sina weibo
    ccdictionary *sinaconfigdict = ccdictionary::create();
    sinaconfigdict->setobject(ccstring::create("your_weibo_appkey"), "app_key");
    sinaconfigdict->setobject(ccstring::create("your_webio_appsecret"), "app_secret");
    sinaconfigdict->setobject(ccstring::create("http://www.sharesdk.cn"), "redirect_uri");
    c2dxsharesdk::setplatformconfig(c2dxplattypesinaweibo, sinaconfigdict);

    // wechat
    ccdictionary *wcconfigdict = ccdictionary::create();
    wcconfigdict->setobject(ccstring::create("your_wechat_appid"), "app_id");
    c2dxsharesdk::setplatformconfig(c2dxplattypeweixisession, wcconfigdict);
    c2dxsharesdk::setplatformconfig(c2dxplattypeweixitimeline, wcconfigdict);
    c2dxsharesdk::setplatformconfig(c2dxplattypeweixifav, wcconfigdict);

    c2dxsharesdk::open(ccstring::create("your_sharesdk_appkey"), false);
}

在share按钮的事件回调函数中调用sharesdk的接口进行社交平台分享:

复制代码 代码如下:

void gamescene::menusharecallback(ref* sender)
{
    dictionary *content = dictionary::create();

    content->setobject(string::create("sharesdk for cocos2d-x 3.0rc2社交分享测试。")
                        , "content");
    content->setobject(string::create("sharesdk分享测试"), "title");
    content->setobject(string::create("http://tonybai.com"), "titleurl");
    content->setobject(string::create("http://tonybai.com"), "url");
    content->setobject(string::create("tony bai"), "site");
    content->setobject(string::create("http://tonybai.com"), "siteurl");
    content->setobject(string::createwithformat("%s", your_local_image_path)
                       , "image");
    content->setobject(string::createwithformat("%d", c2dxcontenttypenews)
                       , "type");

    c2dxsharesdk::showsharemenu(null, content, ccpointmake(100, 100),
                          c2dxmenuarrowdirectionleft, shareresulthandler);
}

void shareresulthandler(c2dxresponsestate state,
                        c2dxplattype plattype,
                        dictionary *shareinfo,
                        dictionary *error)
{
    appdelegate *app = (appdelegate*)application::getinstance();
    switch (state) {
        case c2dxresponsestatesuccess:
            cclog("share ok");
            app->showshareresulttoast("分享成功");
            break;
        case c2dxresponsestatefail:
            app->showshareresulttoast("分享失败");
            cclog("share failed");
            break;
        default:
            break;
    }
}

showshareresulttoast实现如下:

复制代码 代码如下:

void appdelegate::showshareresulttoast(const char *msg)
{
    jnimethodinfo t;
    if (jnihelper::getstaticmethodinfo(t, "your_activity_name",
        "showshareresulttoast", "(ljava/lang/string;)v")) {
        jstring jmsg = t.env->newstringutf(msg);
        t.env->callstaticvoidmethod(t.classid, t.methodid, jmsg);
        if (t.env->exceptionoccurred()) {
            t.env->exceptiondescribe();
            t.env->exceptionclear();
            return;
        }
        t.env->deletelocalref(t.classid);
    }
}

4. java部分代码集成

在gamedemo/proj.android/src下面建立cn/sharesdk路径,将c2dxsharesdksample /proj.android/src/cn/sharesdk下的onekeyshare和sharesdkutils.java copy到gamedemo/proj.android/src/cn/sharesdk下面。

将sharesdk-android-2.3.7.zip解压后的sharesdk for android/src/wxapi copy到gamedemo/proj.android/src/com.tonybai.game/下。

修改gamedemo/proj.android/src/com.tonybai.game/gamedemoactivity.java文件:

复制代码 代码如下:

import android.widget.toast;
import cn.sharesdk.sharesdkutils;

public class gamedemoactivity extends cocos2dxactivity {

    private static context context;

    private static handler notifyhandler = new handler() {
        public void handlemessage(message msg) {
            switch (msg.what) {
                case 1:
                    string message = (string) msg.obj;
                    toast.maketext(context, message,
                      toast.length_short).show();
                    break;
                default:
                    break;
            }
        }
    };

    @override
    protected void oncreate(bundle savedinstancestate) {
        super.oncreate(savedinstancestate);
        context = this;
        sharesdkutils.prepare();
        sharesdkutils.initsdk("your_sharesdk_appkey", true);
    }

    public static void showshareresulttoast(string result) {
        message msg = new message();
        msg.what = 1;
        msg.obj = result;
        notifyhandler.sendmessage(msg);
    }

    @override
    public void ondestroy() {
        sharesdkutils.stopsdk();
        super.ondestroy();
    }
}

三、问题与解决方法

按照上面的集成方法修改后,通过cocos编译app,在模拟器运行gamedemo,点击share,理论上屏幕下方会出现sharesdk的分享窗口,选择“新浪微博”图标,会打开“图文分享”内容窗口,点击窗口右上角的“分享”即可。

【问题1】“图文分享”窗口内容可编辑,并且总是弹出软键盘,影响体验。

 期望:内容不可编辑,默认不弹出软键盘
 解决方法:
      打开proj.android/src/cn/sharesdk/onekeyshare/editpage.java,做如下修改:

      将窗口的软输入方式默认改为soft_input_state_hidden。

复制代码 代码如下:

      public void setactivity(activity activity) {
        super.setactivity(activity);
        if (dialogmode) {
            activity.settheme(android.r.style.theme_dialog);
            activity.requestwindowfeature(window.feature_no_title);
        }
        activity.getwindow().setsoftinputmode(
                   //windowmanager.layoutparams.soft_input_state_always_visible);
                   windowmanager.layoutparams.soft_input_state_hidden);//default: hidden
    }

    在initpageview中增加一行:etcontent.setkeylistener(null)。让窗口内容无法修改。
复制代码 代码如下:
    private void initpageview() {
         … …
        // 文字输入区域
        etcontent = new edittext(getcontext());
        etcontent.setgravity(gravity.left | gravity.top);
        etcontent.setbackgrounddrawable(null);
        etcontent.settext(string.valueof(reqdata.get("text")));
        etcontent.setkeylistener(null);//make the edittext uneditable
        etcontent.setlayoutparams(lpet);
        … …
    }

【问题2】向微博分享,点击“分享”后,过一会程序异常停止。

 原因分析:
        通过调试观察,发现sharesdk在解析从weibo收到的json包时出现内存违法访问。具体位置是在解析一个数组对象时出现的问题。 sharesdk用ccarray来存储json中的数组对象。该问题在cocos2d-x 2.2.2版本中不会出现,但在cocos2d-x 3.0rc2版本中会出现。经代码对比发现,3.0rc2版本中的ccarray的实现与2.2.2 ccarray实现有很大不同,似乎是做了较大重构,暂不能确定是否是3.0rc2版本中ccarray实现的bug。

 解决方法:由于后续的分享结果通知成功与否只需要根据分享的状态来决定,因此我们只需解析出"status"、“action”和“platform” 这三个ccnumber类型字段的值即可。ccarray类型的对象我们并不需要,因此我们只需绕过对array类型字段的解析和存储即可,修改如下:

复制代码 代码如下:

// classes/c2dxsharesdk/android/json/ccjsonconverter.cpp

void ccjsonconverter::convertjsontodictionary(cjson *json, ccdictionary *dictionary)
{
    dictionary->removeallobjects();
    cjson * j = json->child;
    while (j) {
        if (j->type == cjson_number) {
            ref * obj = getjsonobj(j);
            dictionary->setobject(obj, j->string);
        }
        j = j->next;
    }
}

四、其他

在使用sharesdk做社交分享时,注意下面两个现象:
1) 第一次进行微博或微信分享时,会打开授权页面,授权后才能分享成功;
2) 微信分享窗口只有在手机联网状态下才能打开。如果手机无法联网,那微信好友、朋友圈和收藏分享将无法打开分享窗口,也不会有什么提示。