当前位置: 首页 > 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;...

Java 语言特性(面试系列2)

一、SQL 基础 1. 复杂查询 &#xff08;1&#xff09;连接查询&#xff08;JOIN&#xff09; 内连接&#xff08;INNER JOIN&#xff09;&#xff1a;返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)

HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法

树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作&#xff0c;无需更改相机配置。但是&#xff0c;一…...

练习(含atoi的模拟实现,自定义类型等练习)

一、结构体大小的计算及位段 &#xff08;结构体大小计算及位段 详解请看&#xff1a;自定义类型&#xff1a;结构体进阶-CSDN博客&#xff09; 1.在32位系统环境&#xff0c;编译选项为4字节对齐&#xff0c;那么sizeof(A)和sizeof(B)是多少&#xff1f; #pragma pack(4)st…...

java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别

UnsatisfiedLinkError 在对接硬件设备中&#xff0c;我们会遇到使用 java 调用 dll文件 的情况&#xff0c;此时大概率出现UnsatisfiedLinkError链接错误&#xff0c;原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用&#xff0c;结果 dll 未实现 JNI 协…...

蓝桥杯 2024 15届国赛 A组 儿童节快乐

P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡&#xff0c;轻快的音乐在耳边持续回荡&#xff0c;小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下&#xff0c;六一来了。 今天是六一儿童节&#xff0c;小蓝老师为了让大家在节…...

c++ 面试题(1)-----深度优先搜索(DFS)实现

操作系统&#xff1a;ubuntu22.04 IDE:Visual Studio Code 编程语言&#xff1a;C11 题目描述 地上有一个 m 行 n 列的方格&#xff0c;从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子&#xff0c;但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器

第一章 引言&#xff1a;语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域&#xff0c;文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量&#xff0c;支撑着搜索引擎、推荐系统、…...

【算法训练营Day07】字符串part1

文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接&#xff1a;344. 反转字符串 双指针法&#xff0c;两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

现代密码学 | 椭圆曲线密码学—附py代码

Elliptic Curve Cryptography 椭圆曲线密码学&#xff08;ECC&#xff09;是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础&#xff0c;例如椭圆曲线数字签…...