独立游戏之路 -- 获取OAID提升广告收益

Unity 之 获取手机:OAID、IMEI、ClientId、GUID

  • 前言
  • 一、Oaid 介绍
    • 1.1 Oaid 说明
    • 1.2 移动安全联盟(MSA)
  • 二、站在巨人的肩膀上
    • 2.1 本文实现参考
    • 2.2 本文实现效果
    • 2.3 本文相关插件
  • 三、Unity 中获取Oaid
    • 3.1 查看实现源码
    • 3.2 工程配置
    • 3.3 代码实现
    • 3.4 场景搭建
  • 四、总结

前言

在当今的移动互联网时代,Oaid(Open Anonymous ID)成为了广告投放和用户分析的重要工具。对于 Unity 游戏开发者来说,获取安卓手机的 Oaid 可以帮助他们更好地了解用户行为、优化广告投放效果,并提供个性化的游戏体验。

我了解到Oaid还是在TapADN中,TapADN中提到Oaid可以提供更高收益:
在这里插入图片描述

本文将介绍如何在 Unity 中获取安卓手机的 Oaid。


一、Oaid 介绍

1.1 Oaid 说明

Oaid 是一种匿名设备标识符,用于标识移动设备。它与 IMEI 等设备标识符不同,Oaid 不会泄露用户的真实身份信息,同时也能满足广告投放和用户分析的需求。通过获取 Oaid,开发者可以了解用户的设备信息、地理位置、兴趣爱好等,从而为用户提供更加精准的广告投放和个性化的服务。

在 Android 10 版本中,广告渠道商们作为非厂商系统应用将无法获取 IMEI、MAC 等设备信息。旧版本的手机系统在用户手动升级前将保持不变,但是搭载 Android 10 系统的手机系统将不支持获取 IMEI。在一段时间内,将处于新旧版手机系统共存的状态,但是新版手机系统的用户占比将会逐渐提高,会造成新版系统用户无法进行推广渠道的匹配。


1.2 移动安全联盟(MSA)

(MSA)移动安全联盟针对该问题联合国内手机厂商推出补充设备标准体系方案,选择 OAID 字段作为 IMEI 等的替代字段 。广告渠道商选择 OAID 作为 IMEI 的替代字段。OAID 字段是由中国信通院联合华为、小米、OPPO、VIVO 等厂商共同推出的设备识别字段,具有一定的权威性。OAID 的准确性和覆盖率均满足广告场景的使用需求。

关于 OAID 更多信息可参考 MSA移动安全联盟官网: http://www.msa-alliance.cn/col.jsp?id=120

我注册并下载了MAD的SDK,看了开发说明文档,感觉集成操作有点复杂。进而有了本文的实现方式:
在这里插入图片描述



二、站在巨人的肩膀上

2.1 本文实现参考

查到了相关的实现方式【膜拜大佬】

参考链接:

  1. Unity Android获取OAID码
  2. Android_CN_OAID
    在这里插入图片描述

2.2 本文实现效果

下图1是本文最终的实现效果,图2图3是1.3中大佬提供的apk的测试结果参照
在这里插入图片描述

2.3 本文相关插件

在文章开头的资源绑定中有源码和本文使用的最新library-4.2.8.aar包(下载地址),使用是可打开看下是否有新的。
在这里插入图片描述

开头提供的资源包内容:在这里插入图片描述



三、Unity 中获取Oaid

3.1 查看实现源码

在 Unity 中,可以通过调用插件提供的接口来获取 Oaid。具体的获取方法可以参考DeviceIdentifier.java类代码。

在这里插入图片描述

一般来说,需要在游戏启动时获取 Oaid,并将其存储在本地,以便后续使用。


3.2 工程配置

在Project Setting→Player→安卓→Publishing Settings→Build 下勾选如下图所示三项,此时工程会自动生成左侧框到三个文件:
在这里插入图片描述


3.3 代码实现

在settingsTemplate.gradle,添加以下内容,粘贴两次,位置如图所示。

maven { url 'https://developer.huawei.com/repo/' }
maven { url 'https://developer.hihonor.com/repo' }

在这里插入图片描述

新建JAVA代码:

package com.GetOaid;

import android.app.Application;
import android.app.Activity;

import com.unity3d.player.UnityPlayer;

import com.github.gzuliyujiang.oaid.DeviceIdentifier;
import com.github.gzuliyujiang.oaid.IRegisterCallback;

public class OaidWrapper
{
    private Application application;

    public void register()
    {
        application = UnityPlayer.currentActivity.getApplication();
        DeviceIdentifier.register(application, false, new IRegisterCallback() {
                        @Override
                        public void onComplete(String clientId, Exception error) {
                            // do something
                            UnityPlayer.UnitySendMessage("GetOaidSDK", "GetClientIdComplete", clientId);
                        }
                    });
    }

    public String getOAID()
    {
        UnityPlayer.UnitySendMessage("GetOaidSDK", "ShowMsg", DeviceIdentifier.getOAID(application));
        return DeviceIdentifier.getOAID(application);
    }
    
    public String getIMEI() 
    {
        UnityPlayer.UnitySendMessage("GetOaidSDK", "ShowMsg", DeviceIdentifier.getIMEI(application));
        return DeviceIdentifier.getIMEI(application);
    }
          
    public String getClientId() 
    {
       UnityPlayer.UnitySendMessage("GetOaidSDK", "ShowMsg", DeviceIdentifier.getClientId());
       return DeviceIdentifier.getClientId();
    }
                   
    public String getGUID() 
    {
       UnityPlayer.UnitySendMessage("GetOaidSDK", "ShowMsg", DeviceIdentifier.getGUID(application));
       return DeviceIdentifier.getGUID(application);
    }
}

3.4 场景搭建

创建两个Text展示获取到的信息,为了方便调试。在创建四个按钮用于测试主动获取OAID、IMEI、ClientId、GUID。新建GetOaidSDK的物体挂载代码
在这里插入图片描述

新建测试代码:

  1. 需要将3.3中代码挂载到名为GetOaidSDK的物体上。
  2. jo = new AndroidJavaObject("com.GetOaid.OaidWrapper"); 要和上面创建的java文件中的包名和类名对应上:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Android;
using UnityEngine.UI;

public class GetOaidDemo : MonoBehaviour
{
    public Text oaidText;
    public Text megText;
    public Button getOaidBtn;
    public Button getIMEIBtn;
    public Button getClientIdBtn;
    public Button getGUIDBtn;
    public Button getOAIDAAIDBtn;
    
    private static AndroidJavaObject jo;
    
    // 读取设备信息 权限
    private string READ_PHONE_STATE = "android.permission.READ_PHONE_STATE";

    void Start()
    {
        getOaidBtn.onClick.AddListener(OnClickGetOAID);
        getIMEIBtn.onClick.AddListener(OnClickGetIMEI);
        getClientIdBtn.onClick.AddListener(OnClickGetClientId);
        getGUIDBtn.onClick.AddListener(OnClickGetGUID);
        getOAIDAAIDBtn.onClick.AddListener(OnClickGetOAIDAAID);

        // 请求READ_PHONE_STATE权限
        RequestAndCheckPermission();
    }
    
    public void RequestAndCheckPermission()
    {
        Debug.Log("检查请求权限");
        if (!Permission.HasUserAuthorizedPermission(READ_PHONE_STATE))
        {
            Permission.RequestUserPermission(READ_PHONE_STATE);
            // 开始协程等待权限变化
            StartCoroutine(WaitForPermission(READ_PHONE_STATE));
        }
        else
        {
            // 权限已授予,执行操作
            Debug.Log("权限已授予,执行相关操作");
            Register();
        }
    }

    IEnumerator WaitForPermission(string permission)
    {
        float timeWaited = 0f;
        const float timeout = 10f; // 设置超时时间,防止无限等待

        while (!Permission.HasUserAuthorizedPermission(permission) && timeWaited < timeout)
        {
            yield return new WaitForSeconds(0.2f); // 暂停并检查权限状态
            timeWaited += 0.2f;
        }

        if (Permission.HasUserAuthorizedPermission(permission))
        {
            Debug.Log($"Permission {permission} granted after waiting.");
            // 在这里处理权限被授予的逻辑
            ShowMsg("这里可以执行需要该权限的操作.");
        }
        else
        {
            Debug.LogWarning($"Permission {permission} not granted after waiting.");
            // 处理权限请求超时或被拒绝的情况
            ShowMsg($"处理权限请求超时或被拒绝的情况.");
        }
    }

    public void Register()
    {
        if (Application.platform == RuntimePlatform.Android)
        {
            jo = new AndroidJavaObject("com.GetOaid.OaidWrapper");
            jo.Call("register");
        }
    }

    // 渠道clientId 自动获取oaid
    public void GetClientIdComplete(string clientId)
    {
        oaidText.text = "clientId:" + clientId;
        OnClickGetOAID();
    }

    public void OnClickGetOAID()
    {
        oaidText.text += ",取Oaid:";
        if (Application.platform == RuntimePlatform.Android)
        {
            jo = new AndroidJavaObject("com.GetOaid.OaidWrapper");
            string oaidStr = jo.Call<string>("getOAID");
            oaidText.text += oaidStr;
            Debug.Log("取Oaid:" + oaidStr);
        }
    }
    
    public void OnClickGetOAIDAAID()
    {
        oaidText.text += ",getOAIDAAID:";
        if (Application.platform == RuntimePlatform.Android)
        {
            jo = new AndroidJavaObject("com.GetOaid.OaidWrapper");
            string oaidStr = jo.Call<string>("getOAIDAAID");
            oaidText.text += oaidStr;
            Debug.Log("getOAIDAAID:" + oaidStr);
        }
    }
    
    public void OnClickGetIMEI()
    {
        oaidText.text += ",getIMEI:";
        if (Application.platform == RuntimePlatform.Android)
        {
            jo = new AndroidJavaObject("com.GetOaid.OaidWrapper");
            string oaidStr = jo.Call<string>("getIMEI");
            oaidText.text += oaidStr;
            Debug.Log("getIMEI:" + oaidStr);
        }
    }

    public void OnClickGetClientId()
    {
        oaidText.text += ",getClientId:";
        if (Application.platform == RuntimePlatform.Android)
        {
            jo = new AndroidJavaObject("com.GetOaid.OaidWrapper");
            string oaidStr = jo.Call<string>("getClientId");
            oaidText.text += oaidStr;
            Debug.Log("getClientId:" + oaidStr);
        }
    }

    public void OnClickGetGUID()
    {
        oaidText.text += ",getGUID:";
        if (Application.platform == RuntimePlatform.Android)
        {
            jo = new AndroidJavaObject("com.GetOaid.OaidWrapper");
            string oaidStr = jo.Call<string>("getGUID");
            oaidText.text += oaidStr;
            Debug.Log("getGUID:" + oaidStr);
        }
    }

    public void ShowMsg(string msg)
    {
        megText.text += "\n" + msg;
        Debug.Log("msg:" + msg);
    }
}

四、总结

在获取和使用 Oaid 时,需要遵守相关的法律法规和隐私政策。不得将 Oaid 用于非法用途,不得泄露用户的隐私信息。

获取安卓手机的 Oaid 对于 Unity 游戏开发者来说具有重要的意义。通过获取 Oaid,开发者可以更好地了解用户行为、优化广告投放效果,并提供个性化的游戏体验。在获取 Oaid 时,需要遵守相关规定,确保获取的 Oaid 准确性,并及时更新 Oaid。希望本文对 Unity 游戏开发者有所帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/691796.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

金融科技:跨境支付的新引擎,开启全球化支付新时代

一、引言 在全球经济一体化的今天,跨境支付作为连接各国经贸往来的重要桥梁,其便捷性、安全性和效率性成为了各国企业和消费者关注的焦点。金融科技,作为现代金融与传统科技深度融合的产物,正以其独特的创新力和推动力,成为跨境支付领域的新引擎,引领着全球化支付新时代…

基于SSM的旅游民宿预定系统【源码】【运行教程】

基于SSM的旅游民宿预定系统 一、项目介绍1. 游客功能2. 管理员功能3. 高级功能 二、项目技术栈三、项目运行四、项目演示总结 大家好&#xff0c;这里是程序猿代码之路&#xff01;随着旅游业的快速发展&#xff0c;民宿作为一种独特的住宿方式越来越受到游客的喜爱。为了提升用…

Android端信号处理总结

最早之前不管是视频录制还是视频直播&#xff0c;都是从麦克风获取音频后&#xff0c;直接交编码器&#xff0c;封装复用到不同媒体格式。在后面在IM场景中做短语音消息、短语音消息转文本以及语音输入设计到语音识别&#xff0c;也仍然是直接从麦克风拿数据。在整个语音SDK设计…

【JavaScript】内置对象 - 字符串对象 ④ ( 根据索引位置返回字符串中的字符 | 代码示例 )

文章目录 一、根据索引位置返回字符串中的字符1、charAt 函数获取字符2、charCodeAt 函数获取字符 ASCII 码3、数组下标获取字符 String 字符串对象参考文档 : https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String 一、根据索引位置返回…

新火种AI|超越苹果成为市值第二大公司!英伟达的时代已然来临...

美东时间周三&#xff08;6月5日&#xff09; &#xff0c;人工智能领域的龙头公司英伟达开始发力&#xff0c;其股票实现大涨&#xff0c;幅度超过5 %&#xff0c;刷新历史新高。更重要的是&#xff0c;历经了这一波的上涨&#xff0c;英伟达的市值突破了3万亿美元。截至当日收…

嵌入式 Linux LED 驱动开发实验学习

I.MX6U-ALPHA 开发板上的 LED 连接到 I.MX6ULL 的 GPIO1_IO03 这个引脚上&#xff0c;进行这个驱动开发实验之前&#xff0c;需要了解下地址映射。 地址映射 MMU 全称叫做 MemoryManage Unit&#xff0c;也就是内存管理单元。在老版本的 Linux 中要求处理器必须有 MMU&#x…

香港电讯荣获广东省香港商会「2023金领航奖」

&#x1f389;近日&#xff0c;由香港贸易发展局与广东省香港商会联合主办的「粤港服务业合作交流会 暨 2023金领航奖颁奖典礼」在广州举行&#xff0c;香港电讯非常荣幸获颁「卓越企业大奖」&#x1f3c6; &#x1f3c6;「金领航奖」由广东省香港商会于2018年创办&#xff0c;…

常见的api: BigInteger

一.获取一个大的随机整数 1.代码: BigInteger bd1 new BigInteger(4, new Random());System.out.println(bd1); 2.打印的结果:2 3.注释获取的是0-16之间的随机整数 二.获取一个指定的大的数 1.代码&#xff1a; BigInteger bd2 new BigInteger("100");System.o…

Science刊发!乌普萨拉大学最新神经形态触觉人造皮肤可快速精准识别物体

当前&#xff0c;人形机器人使用的传统电子皮肤在处理触觉感知信息方面的能力并不强&#xff0c;尤其是在时间信息编码和快速特征提取方面存在一定的局限性。简单来说就是机器人无法完成在接触到物品的瞬间&#xff0c;判断用怎样的力度去对该物品做出反应。尽管多模态大模型和…

171.二叉树:二叉树的所有路径(力扣)

代码解决 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr, right(nullptr) {}* Tree…

C 语言实现在终端里输出二维码

Mac 环境安装二维码库 brew install qrencode安装过程报权限问题执行以下命令 sudo chown -R 用户名 /usr/local/include /usr/local/lib chmod uw /usr/local/include /usr/local/lib#include <stdio.h> #include <qrencode.h>void print_qr_code(QRcode *qrcode…

【学习笔记】解决 VMware Workstation 17 Player 和主机之间无法复制粘贴的问题

【学习笔记】解决 VMware Workstation 17 Player 和主机之间无法复制粘贴的问题 使用VMware Workstation 17 Player&#xff0c;再上面安装 Ubuntu &#xff0c;安装完之后&#xff0c;需要和主机之间进行复制粘贴。 首先安装了VMware Tools。 在打开的页面下把 VMwareTools…

【数据可视化系列】使用Python和Seaborn绘制相关性热力图

热力图&#xff08;Heatmap&#xff09;是一种数据可视化工具&#xff0c;它通过使用颜色的深浅来展示数据矩阵中数值的大小或密度。在热力图中&#xff0c;每种颜色的深浅代表数据的一个特定值或值的范围&#xff0c;通常使用红色、黄色和绿色等颜色渐变来表示数据的热度&…

能在电脑和手机上使用的便签app 好用的便签软件

随着科技的日新月异&#xff0c;越来越多的软件被开发出来&#xff0c;极大地便利了我们的工作和生活。其中&#xff0c;便签软件凭借其便捷的记录功能&#xff0c;受到了广大用户的喜爱。特别是那些能在电脑和手机上同步使用的便签app&#xff0c;更是为我们的工作和生活带来了…

抖抖分析师和抖音分析有什么区别?

"抖抖分析师"和"抖音分析"虽然都与抖音这个平台有关&#xff0c;但是二者的含义有很大的区别。 首先&#xff0c;抖抖分析师通常指的是专门对抖音平台进行各种数据分析、用户行为研究、内容趋势预测等工作的人员。他们可能会洞察用户在抖音上的行为习惯&a…

【SQLAlChemy】如何定义ORM模型,如何映射到数据库?

定义ORM模型并映射到数据库 创建 ORM 基类 使用 declarative_base 根据 engine 来创建一个 ORM 基类。 from SqlAIchemy.LinkDB.main import engineBase declarative_base()创建自定义类 用上边定义的 Base 类来实现自己的 ORM 类。 __tablename__ 类属性&#xff0c;可以…

Linux的目录结构介绍和环境变量的设置

目录 前言一、系统环境二、Linux的目录结构2.1 Linux目录结构介绍2.2 Linux文件的路径描述2.2.1 绝对路径2.2.2 相对路径2.2.3 特殊的路径符 三、Linux的环境变量设置3.1 环境变量PATH3.2 关于$符的使用3.3 环境变量的设置 总结 前言 本篇文章介绍Linux的目录结构和环境变量的…

嵌入式linux系统中利用I2C控制器应用开发详解

大家好,今天主要给大家分享一下,在linux系统上如何使用I2C进行应用开发详解。 l2C (Inter一Integrated Circuit BUS)是I2C BUS简称.中文为集成电路总线.是目前应用最广泛的总线之一。和IMX6ULL有些相关的是.刚好该总线是NXP前身的PHLIPS 设计。 第一:I2C协议概述 …

spring源码解析-(2)Bean的包扫描

包扫描的过程 测试代码&#xff1a; // 扫描指定包下的所有类 BeanDefinitionRegistry registry new SimpleBeanDefinitionRegistry(); // 扫描指定包下的所有类 ClassPathBeanDefinitionScanner scanner new ClassPathBeanDefinitionScanner(registry); scanner.scan(&quo…

HTML静态网页成品作业(HTML+CSS)—— 家乡南宁介绍网页(2个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有2个页面。 二、作品演示 三、代…