栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 游戏开发 > 其他

Unity手游邀请拉新活动解决方案

其他 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Unity手游邀请拉新活动解决方案

文章目录
  • 前言
  • 流程
    • 1.为每个玩家生成唯一邀请码。
    • 2.将邀请码与链接地址生成二维码。
      • 1. Zxing插件。
      • 2. 通过草料的API接口获取。
    • 3.生成游戏落地页。
    • 4.分享到微信好友/朋友圈。
      • 【安卓】
      • 【IOS】
    • 5.使用OpenInstall传递启动参数。
      • 【安卓端】
      • 【IOS】
      • 【H5落地页】
  • 结束

前言

当前手游市场每天可能有几十上百款游戏上线,竞争这么激烈的情况下,流量对游戏的重要性不言而喻。
今天就在此记录整理一下我最近在项目中的解决方案:邀请拉新


流程

需求大概如下。

  1. 为每个玩家生成唯一邀请码。
  2. 将邀请码与链接地址生成二维码。
  3. 生成游戏落地页。
  4. 分享到微信好友/朋友圈。
  5. 使用OpenInstall传递启动参数。
  6. 识别启动参数,进入邀请流程。
1.为每个玩家生成唯一邀请码。

服务器用node写的,根据玩家在数据库的唯一id转换成MASK长度进制的邀请码。起初是26个字母+10个数字来的,不过某些字母跟数字不容易区分,就剔除掉了。
全用大写是因为真正输入的时候不断的切换大小写对玩家体验非常不友好。

const BIND_MASK = ["A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",    "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"];
function GetBindCode(value) {
    var length = BIND_MASK.length;
    var arr = [];
    while (true) {
        if (value < length) {
            arr.push(value);
            break;
        }
        var intDivide = value % length;
        value = (value - intDivide) / length;
        arr.push(intDivide);
    }
    arr.reverse();
    var bindCode = "";
    for (let item of arr) {
        var index = item;
        if (index == 0) {
            index = length;
        }
        bindCode += BIND_MASK[index - 1];
    }
    return bindCode;
}
2.将邀请码与链接地址生成二维码。

网上解决方案参考比较多。参考跳转

1. Zxing插件。

Zxing是一款本地生成二维码的插件,使用简单易上手。前端是untiy,实现如下。
代码搬运工~~

public Texture2D CreateQRCode(string content, Rect rect)
    {
		Texture2D encoded = new Texture2D((int)rect.width, (int)rect.height);
        if (content != null)
        {
            Color32[] color32 = Encode(content, (int)rect.width, (int)rect.height);
            encoded.SetPixels32(color32);   //根据转换来的32位颜色值来计算二维码的像素
            encoded.Apply();    //生成二维码
        }
        try
        {
            byte[] pngData = encoded.EncodeToPNG();     //将Texture2D转码成png格式的字节数据

            File.WriteAllBytes(path, pngData);
        }
        catch (Exception ioe)
        {
            Debug.LogException(ioe);    //输出图片保存异常信息
        }
        return encoded;
    }
private static Color32[] Encode(string textForEncoding, int width, int height)
    {
        BarcodeWriter writer = new BarcodeWriter
        {
            Format = BarcodeFormat.QR_CODE,
            Options = new QrCodeEncodingOptions
            {
                Height = height,
                Width = width,
                CharacterSet = "UTF-8",
            }
        };

        return writer.Write(textForEncoding);
    }

结果如下

但是在打包到安卓端的时候生成报错

看样子是插件内部的问题,最终不了了之。使用了第二种方法。

[补充]:应该是某个版本的Zxing有问题,我从网上又试了几个版本,测试这个版本是可以用的

网盘链接:https://pan.baidu.com/s/12rQ7vuen9JiO9p5VMag18w
提取码:i1qc

2. 通过草料的API接口获取。

不过这种方式的缺点也很明显。

  • 用户体验不好,需要有网络支持。
  • 经测试,text=后如果携带多个参数,草料只会判断第一个参数有效。
    比如"https://cli.im/api/qrcode/code?text=" + “http://baidu.com?name=1&pwd=2&bindCode=3”。最终生成的二维码的链接是"https://cli.im/api/qrcode/code?text=" + “http://baidu.com?name=1”。第一个之后的参数

&pwd=2&bindCode=3"

都被忽略掉了。
下面的其实就是用 | 把各个字段拼接了一下。

bindData.ToEntryString()

	var url = "https://cli.im/api/qrcode/code?text=" + url + $"?bindData={bindData.ToEntryString()}";
	UnityWebRequest uwr = UnityWebRequest.Get(url);
    yield return uwr.SendWebRequest();

    if (uwr.isHttpError || uwr.isNetworkError)
    {
        Debug.Log(uwr.error);
        yield break;
    }
    else
    {
        string s = uwr.downloadHandler.text.Substring(uwr.downloadHandler.text.IndexOf(") + 12, uwr.downloadHandler.text.Length - (uwr.downloadHandler.text.IndexOf(") + 12));
        string result = s.Substring(0, s.IndexOf("""));
        UnityWebRequest newu = UnityWebRequest.Get(result);
        newu.downloadHandler = new DownloadHandlerTexture(true);
        yield return newu.SendWebRequest();
        var dlh = newu.downloadHandler as DownloadHandlerTexture;
        File.WriteAllBytes(localPath, dlh.texture.EncodeToPNG());
        Debug.Log(localPath);
        img_qrCode.texture = dlh.texture;
	}
3.生成游戏落地页。

二维码生成后,怎么把二维码放到落地页又成了一个问题。
有看到说是根据像素,把二维码放到预先生成好的图片里。个人感觉不是很直观。
用了一个很老土的办法,把二维码渲染到一个rawImage中,然后落地页的样子,用单独的正交摄像机去拍照。

代码也是非常简单

private IEnumerator TakePhoto()
    {
        Debug.Log("开始拍照");
        yield return new WaitForEndOfFrame();
        RenderTexture.active = mCamera.targetTexture;
        var sharePost = new Texture2D(mCamera.targetTexture.width, mCamera.targetTexture.height);
        sharePost.ReadPixels(new Rect(0, 0, sharePost.width, sharePost.height), 0, 0);
        sharePost.Apply();
        if (!Directory.Exists(dir))
        {
            Directory.CreateDirectory(dir);
        }
        File.WriteAllBytes(path, sharePost.EncodeToPNG());
        Debug.Log("拍照完毕");
    }
4.分享到微信好友/朋友圈。

上链接~微信官方文档

PS:首先要做的就是根据官方文档把该配置的都配置完毕,否则出了问题之后,定位问题的时间都比重新接入要久。

【安卓】

注意这句话


当时忽略了这点,发现在小米10上测试的时候提示要用fileProvider的方式去分享,后来改了之后就OK了。

在论坛里看到有一些同学不知道怎么用fileProvider。我把自己的实现贴在下面。

    //scene 0-分享到对话  1-分享到朋友圈  2-分享到收藏  imgPath = "share.png"
    public void ShareToWechat(int scene, String imgPath) {
        String filePath = getExternalFilesDir(null) + "/sharedata/" + imgPath;
        File file = new File(filePath);
        String contentPath = getFileUri(this, file);
        WXEntryActivity.ShareToWechat(scene, filePath, contentPath);
    }
    public String getFileUri(Context context, File file) {
        if (file == null || !file.exists()) {
            return null;
        }

        Uri contentUri = FileProvider.getUriForFile(context,
                "com.abcd.qmddx.fileProvider",  // 要与`AndroidManifest.xml`里配置的`authorities`一致,假设你的应用包名为com.example.app
                file);

        // 授权给微信访问路径
        context.grantUriPermission("com.tencent.mm",  // 这里填微信包名
                contentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);

        return contentUri.toString();   // contentUri.toString() 即是以"content://"开头的用于共享的路径
    }
//scene 0-分享到对话  1-分享到朋友圈  2-分享到收藏
    public static void ShareToWechat(int scene, String imgPath, String uri) {
    //imgPath是真实路径
        Bitmap bmp = BitmapFactory.decodeFile(imgPath);
//初始化 WXImageObject 和 WXMediaMessage 对象
        WXImageObject imgObj = new WXImageObject();
        if (checkVersionValid() && checkAndroidNotBelowN()) {
        //这里是uri路径。
            imgObj.setImagePath(uri);
        } else {
            imgObj.setImagePath(imgPath);
        }

        WXMediaMessage msg = new WXMediaMessage();
        msg.mediaObject = imgObj;
        msg.description = "XXXXXXXXXXX";
        msg.title = "XXXXXXXX";
//设置缩略图
        Bitmap thumbBmp = Bitmap.createScaledBitmap(bmp, 75, 134, true);
        bmp.recycle();
        msg.thumbData = Bitmap2Bytes(thumbBmp);
//构造一个Req
        SendMessageToWX.Req req = new SendMessageToWX.Req();
        req.transaction = String.valueOf(System.currentTimeMillis());
        req.message = msg;
        req.scene = scene;

//        req.userOpenId = getOpenId();
//调用api接口,发送数据到微信
        MainApplication.sApi.sendReq(req);
    }
【IOS】
void _shareToWechatSession(){
    NSLog(@"_shareToWechatSession");
	//要先获取这个地址
    NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    NSString *filePath = [documentPath stringByAppendingPathComponent:@"/sharedata/share.png"];
    UIImage *image = [UIImage imageNamed:filePath];

    NSData* imageData = UIImageJPEGRepresentation(image, 0.7);
       
    WXImageObject *imageObject = [WXImageObject object];
    imageObject.imageData = imageData;

    WXMediaMessage *message = [WXMediaMessage message];
	//thumbData不能太大
    message.thumbData = UIImageJPEGRepresentation(image, 0.1);
    message.title = @"XXXXX";
    message.description = @"XXXXX";
    message.mediaObject = imageObject;

    SendMessageToWXReq *req = [[SendMessageToWXReq alloc] init];
    req.bText = NO;
    req.message = message;
    req.scene = WXSceneSession;

    [WXApi sendReq:req completion:^(BOOL success) { NSLog(@"唤起微信:%@", success ? @"成功" : @"失败");  }];
    
}
5.使用OpenInstall传递启动参数。

带参数的落地页生成好了,怎么让玩家在扫码下载游戏之后携带启动参数进入游戏呢?本着不要重复造轮子的想法,我找到一个第三方插件openInstall。接入文档
简单易上手。因为我用的是Unity开发,就下载了unity的SDK。
接入后我们只需要关系 getInstallFinish这个回调函数。
因为之前我通过 | 将多参数合并在一起了。现在需要再拆分开。所以有了下面的字符串替换的部分。

    // callback
    public void getInstallFinish(OpenInstallData installData)
    {
        Debug.Log("OpenInstallSample getInstallFinish : 渠道编号=" + installData.channelCode + ",自定义数据=" + installData.bindData);
        if (string.IsNullOrEmpty(installData.bindData))
        {
            Debug.Log("没有启动参数");
            return;
        }
        var str = installData.bindData.Replace("{", "").Replace("}", "").Replace(""","");
        var arr = str.Split('|');
        ApprData.BindData bindData = new ApprData.BindData() { channel = arr[0], bindCode = arr[1] };
        LoginManager.bindData = bindData;
    }

注意上传包之后,官网会进行检测,之后会给你生成对应的参数以及修改意见,按照修改意见接入,测试。

【安卓端】

安卓端只需要按照官方文档配置AndroidManifest.xml文件即可。

【IOS】

根据官方文档接入,理想情况下 配置参数即可。

不理想情况比较多。因为按照我个人接入习惯来说,一般都要重写AppController的,尽量做到与导出工程解耦。这时候就要注意下面这句话,官方这里也有特别说明。



要注意的是这里用的

OpenInstallUnity3DCallBack defaultManager


我当时就没有注意这点,根据官方文档接入了,最后一直获取不到启动参数。注意不是下面的

OpenInstallSDK continueUserActivity

【H5落地页】

OpenInstall很好的一点是傻瓜式接入。甚至连H5落地页都写好了。我把自己的落地页放进来,供学习交流。
安卓与IOS都接入完毕后,打开落地页,在安卓平台下就会打开/下载游戏,IOS打开/App Store跳转 游戏。
启动参数可以从官方SDK的getWakeupFinish中获取。

public void getWakeupFinish(OpenInstallData wakeupData)
    {
        Debug.Log("OpenInstallSample getWakeupFinish : 渠道编号=" + wakeupData.channelCode + ", 自定义数据=" + wakeupData.bindData);
        //wakeupResult.text = "拉起参数:" + JsonUtility.ToJson(wakeupData);
    }




    

    
    一起来学习
    






    
结束

欢迎各位同学一起交流~

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/902331.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号