当前位置: 首页 > news >正文

独立游戏之路 -- 获取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() {@Overridepublic void onComplete(String clientId, Exception error) {// do somethingUnityPlayer.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 自动获取oaidpublic 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 游戏开发者有所帮助。

相关文章:

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

Unity 之 获取手机&#xff1a;OAID、IMEI、ClientId、GUID 前言一、Oaid 介绍1.1 Oaid 说明1.2 移动安全联盟(MSA) 二、站在巨人的肩膀上2.1 本文实现参考2.2 本文实现效果2.3 本文相关插件 三、Unity 中获取Oaid3.1 查看实现源码3.2 工程配置3.3 代码实现3.4 场景搭建 四、总…...

反转链表 (oj题)

一、题目链接 https://leetcode.cn/problems/reverse-linked-list/submissions/538124207 二、题目思路 1.定义三个指针&#xff0c;p1先指向NULL p2指向头结点 p3指向第二个结点 2.p2的next指向p1。然后移动指针&#xff0c;p1来到p2的位置&#xff0c;p2来到p3的位置&…...

Mysql使用中的性能优化——批量插入的规模对比

在《Mysql使用中的性能优化——单次插入和批量插入的性能差异》中&#xff0c;我们观察到单次批量插入的数量和耗时呈指数型关系。 这个说明&#xff0c;不是单次批量插入的数量越多越好。本文我们将通过实验测试出本测试案例中最佳的单次批量插入数量。 结论 本案例中约每次…...

TCP为什么握手是三次,而挥手是四次

TCP&#xff08;传输控制协议&#xff09;使用三次握手&#xff08;3WHS&#xff09;来建立一个可靠的连接&#xff0c;并使用四次挥手&#xff08;4WHS&#xff09;来终止连接。以下是每个步骤的详细解释&#xff1a; 三次握手&#xff08;3WHS&#xff09;建立连接&#xff…...

前端面试题大合集9----TypeScript

目录 一、TypeScript 中静态类型的概念及其好处 二、如何在 TypeScript 的接口中定义可选属性&#xff1f; 三、解释 TypeScript 中联合类型的概念并提供示例 四、TypeScript 中的类型断言是什么&#xff1f; 五、TS中泛型是什么&#xff1f; 六、解释 TypeScript 中的“…...

Linux:动态库和静态库的编译与使用

目录 1.前言 2.静态链接库 3.静态链接库生成步骤 4.静态链接库的使用 5.动态链接库 6.动态链接库生成步骤 7.动态链接库的使用 8.动态链接库无法加载 9.解决动态链接库无法加载问题 前言 在《MinGW&#xff1a;从入门到链接库》博客中简单介绍了如何编译动态链接库和静态链接库…...

【Pyqt6 学习笔记】DIY一个二维码解析生成小工具

文章目录 Pycharm 配置QtDesignerPyUIC基本模板 代码示例依赖包main.pyscreen_shot_module.pyuntitled.pyuntitled.ui Pycharm 配置 摘自PyQT6的从零开始在Pycharm中配置与使用——蹦跑的蜗牛 pip install PyQt6 PyQt6-toolsQtDesigner File -> Settings -> External …...

关于xilinx srio ip复位问题

关于xilinx srio ip复位问题 语言 &#xff1a;Verilg HDL 、VHDL EDA工具&#xff1a; Vivado 关于xilinx srio ip复位问题一、引言二、FPGA 之间 srio通信复位处理复位时序不同步&#xff1a;SRIO 模块未正确初始化&#xff1a;等待复位完成的时间不足&#xff1a;SRIO 配置…...

04 uboot 编译与调试

新手不需要详细掌握 uboot,只需要知道它是一个什么东西即可,工作中也只是改一些参数而已。 1、uboot 是什么 Linux 系统要启动就必须需要一个 bootloader 程序,也就说芯片上电以后先运行一段 bootloader 程序。这段 bootloader 程序会先初始化 DDR 等外设,然后将 Linux 内…...

【机器学习】机器学习与医疗健康在智能诊疗中的融合应用与性能优化新探索

文章目录 引言机器学习与医疗健康的基本概念机器学习概述监督学习无监督学习强化学习 医疗健康概述疾病预测诊断辅助个性化治疗方案制定 机器学习与医疗健康的融合应用实时健康监测数据预处理特征工程 疾病预测与优化模型训练模型评估 诊断辅助与优化深度学习应用 个性化治疗方…...

在线OJ项目测试(selenium+Junit5)

目录 在线OJ项目测试的思维导图 在线OJ的UI自动化测试 测试一&#xff1a;检查未登录时的页面访问以及一些未登录时的非法操作 测试二&#xff1a;测试注册界面 测试三&#xff1a;测试登录界面 测试四&#xff1a;测试题目列表界面 测试五&#xff1a;测试题目详情界面…...

计算机系统基础笔记(12)——控制

前言 在持续输出ing 一、条件码 1.处理器状态&#xff08;x86-64&#xff0c;部分的&#xff09; 当前程序的执行信息 ◼ 临时数据 ◼ 运行时栈的位置&#xff08;栈顶&#xff09; ◼ 当前代码控制点的位置&#xff08;即将要执行的指令地址&#xff09; ◼ 最近一次指令执…...

使用RedissonClient的管道模式批量查询key

1.场景 遇到了一个场景&#xff0c;在客户给我们推送的数据中&#xff0c;咋1分钟左右&#xff0c;会有相同车辆vehicle 和时间 gpstime一样的数据&#xff0c;这类数据呢&#xff0c;我们认为是重复数据&#xff0c;需要过滤的 把相同 vehicle 和 gpstime 作为key存入到redis中…...

UR机器人通信汇总

文章目录 一、概述二、UR机器人通信2.1UR通信协议2.2 UR通信端口 三、UR机器人通信端口类型3.1 Modbus TCP端口&#xff08;502端口&#xff09;3.2 Dashboard端口&#xff08;29999端口&#xff09;3.3 上位机编程端口&#xff08;30001/30002/30003端口&#xff09;3.3.1 URS…...

AI学习指南机器学习篇-使用ID3算法构建决策树

AI学习指南机器学习篇-使用ID3算法构建决策树 介绍ID3算法 ID3&#xff08;Iterative Dichotomiser 3&#xff09;是一种用于构建决策树的经典机器学习算法。它是由Ross Quinlan于1986年提出的&#xff0c;是一种基于信息论的算法&#xff0c;用于从一组特征中选择最佳特征来…...

React实战(一)初始化项目、配置router、redux、axios

(一)初始化项目 1.安装项目 npx create-react-app 项目名 编译报错&#xff1a; 解决办法&#xff1a;安装最新的babel-preset-react-app npm install babel-preset-react-applatest 2.配置项目 (1)配置文件目录 (2)使用craco配置webpack.config npm install craco/crac…...

高质量 HarmonyOS 权限管控流程

高质量 HarmonyOS 权限管控流程 在 HarmonyOS 应用开发过程中&#xff0c;往往会涉及到敏感数据和硬件资源的调动和访问&#xff0c;而这部分的调用就会涉及到管控这部分的知识和内容了。我们需要对它有所了解&#xff0c;才可以在应用开发中提高效率和避免踩坑。 权限管控了…...

java里面封装https请求工具类2

其他写法 https://blog.csdn.net/weixin_44372802/article/details/132620809?spm1001.2014.3001.5501 encodeJson 是请求参数的密文格式&#xff08;大公司都是要对请求参数加密的&#xff09; ResponseBean 是自己或者对方定义的返回内容参数 public ResponseBean sendByEnc…...

前端面试题日常练-day59 【面试题】

题目 希望这些选择题能够帮助您进行前端面试的准备&#xff0c;答案在文末 1. 在PHP中&#xff0c;以下哪个符号用于比较两个值的相等性&#xff1f; a) b) c) d) ! 2. PHP中的预定义变量$_POST用于获取什么类型的数据&#xff1f; a) 用户的输入数据 b) 浏览器发送的请…...

计算机小问题(4)--关闭联想电脑的小组件

打开联想软件管家&#xff0c;关闭即可 &#xff08;今天弄了好久才找到&#xff0c;记录一下&#xff09;...

synchronized 学习

学习源&#xff1a; https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖&#xff0c;也要考虑性能问题&#xff08;场景&#xff09; 2.常见面试问题&#xff1a; sync出…...

Java如何权衡是使用无序的数组还是有序的数组

在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略

本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装&#xff1b;只需暴露 19530&#xff08;gRPC&#xff09;与 9091&#xff08;HTTP/WebUI&#xff09;两个端口&#xff0c;即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:

根据万维钢精英日课6的内容&#xff0c;使用AI&#xff08;2025&#xff09;可以参考以下方法&#xff1a; 四个洞见 模型已经比人聪明&#xff1a;以ChatGPT o3为代表的AI非常强大&#xff0c;能运用高级理论解释道理、引用最新学术论文&#xff0c;生成对顶尖科学家都有用的…...

css3笔记 (1) 自用

outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size&#xff1a;0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格&#xff…...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2

每日一言 今天的每一份坚持&#xff0c;都是在为未来积攒底气。 案例&#xff1a;OLED显示一个A 这边观察到一个点&#xff0c;怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 &#xff1a; 如果代码里信号切换太快&#xff08;比如 SDA 刚变&#xff0c;SCL 立刻变&#…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...

SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)

上一章用到了V2 的概念&#xff0c;其实 Fiori当中还有 V4&#xff0c;咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务)&#xff0c;代理中间件&#xff08;ui5-middleware-simpleproxy&#xff09;-CSDN博客…...

AGain DB和倍数增益的关系

我在设置一款索尼CMOS芯片时&#xff0c;Again增益0db变化为6DB&#xff0c;画面的变化只有2倍DN的增益&#xff0c;比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析&#xff1a; 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...

深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用

文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么&#xff1f;1.1.2 感知机的工作原理 1.2 感知机的简单应用&#xff1a;基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...