Unity2022接入Google广告与支付SDK、导出工程到Android Studio使用JDK17进行打包完整流程与过程中的相关错误及处理经验总结
注:因为本人也是第一次接入广告与支付SDK相关的操作,网上也查了很多教程,很多也都是只言片语或者缺少一些关键步骤的说明,导致本人也是花了很多时间与精力踩了很多的坑才搞定,发出来也是希望能帮助到其他人在遇到相似问题的时候能少踩坑少熬夜少加班,至少能提供一个解决问题的思路,理论上该经验可适用于任意版本的SDK接入,总归思路都是差不多的,文章内容可能会不定期修改,如果存在不准确或理解错误的地方,可评论区通知我进行修改
注意翻墙问题,毕竟国内对于国外的网站很多是没办法进行访问的。
文章中所使用的各软件及插件版本说明(可能存在遗留的地方,可能后期修改补档吧,大部分通用没问题大概率不会改了)
Unity:2022.3.15
Unity所使用的 Google SDK:9.0.0(一开始使用的8.5版本,结果刚好弄完的时候该版本弃用了,只能换成了9.0.0,但9.0中所使用的SDK版本是23版本的,23版本需要JDK17与Gradle8.0才能编译,所以只能导出到Android Studio进行编译)
Google Play 支付采用的是接入原生支付进行操作的,版本为6.0,文章中主要包含一些经验总结,因为思路总体也是参考了其他人的文章
1、广告SDK接入
Google SDK获取地址:Google 广告 SDK Mobile Ads SDK (Unity)
需要关注的点:
1、广告SDK弃用时间,相关链接:弃用和停用 | Unity | Google for Developers ,注意其中的版本信息对应的是Android原生SDK的版本信息,新手注意别搞混了,Unity所使用的插件中的版本信息需要从Github中对应版本的日志中进行查看
2、Android Gradle插件可使用的Gradle版本,相关链接:Android Gradle 插件 8.7 版本说明 | Android Studio | Android Developers,注意让看这个主要是为了后边使用Android Studio进行编译的时候,知道该用那个版本进行编译
3、广告SDK接入流程并不复杂,心平气和看完操作步骤就可以搞定,别像我一样的因为加班太多太过浮躁导致简单的问题复杂化,所以具体接入步骤不做详细说明,根据SDK获取的界面中按照官方的步骤进行接入即可,需注意的关注的是,SDK所使用的JDK版本、Gradle版本是否与当前Unity版本是否兼容,例如本人使用的是Unity2022.3.15+广告SDK的9.0版本,而Unity2022没有办法更换使用JDK17(至少我没找到办法),所以需要导出到Android Studio进行打包操作
4、打包时google Setting中的应用id一定要填写,不填写的话,就算打包成功了,进行安装后同样也会因为ID未找到从而无法成功运行应用
5、接入的SDK版本较低时,SDK被弃用后,可以在安卓日志中看到Google的通知,广告不会正常播放,效果就是点击后没有任何效果
6、成功接入广告并打包后,正常情况下就可以看到广告的内容
7、播放广告后的奖励回调函数,记得一定使用协程进行操作,也就说传入的回调函数可以是普通函数,但关于传入的回调函数的最终执行时一定使用一个协程去运行, 因为直接进行调用,会导致应用直接就给闪退了
关于广告的部分就先到这里,因为广告的接入不难,难点都在打包的过程中了
2、原生支付SDK接入
接入原生支付后(也就是加入jar包后),需要打包后才能看到效果在编辑器中是没有办法看到效果的
先说明一下思路来源相关链接:
Unity接入GooglePlay内购V4 V5 V6(源生Android方式)_unity接入google内购-CSDN博客
后台UnityPlayer.UnitySendMessage不生效(Android) | 梓喵出没
第一个链接为参考原生支付接入的方法,而第二个则是对UnityPlayer.UnitySendMessage调用一次后再次进行调用时,没有任何反应的处理,至于为什么没有反应,简单来说就是被sendMessage调用的函数代码所在的activity需要保持在前台,一旦被切换为其他activity后,再次调用代码就没有什么效果了,我解释的可能太过笼统或者不正确,详细的解释请自行百度吧,或者遇到了的时候自然就懂了,所以这里推荐对于Unity内部方法的调用采用第二个链接中的方法,直接一劳永逸,即编写一个C#脚本继承AndroidJavaProxy类,用于实现Java代码中的接口,在初始化java对象时,new一个实现了Java接口函数的类同时传递给java对象,并保存一下对对象的引用,然后呢,直接把收到的对象当成一个接口使用就好了例如下边实现
C#代码:
代码只有部分啊,别全抄了,只是做参考,因为该代码也只是对第一个链接中的代码修改后得到的
public class IAPMessage : AndroidJavaProxy{public IAPMessage() : base("com.XXX.unitytogoolgleplaylib.IAPMessage"){}#region callback from Objective-c/JAR//获取到产品列表回调public void RecieveProductInfos(string jsonData){if (string.IsNullOrEmpty(jsonData)) return;var infoData = JsonConvert.DeserializeObject<IAPProductInfoData>(jsonData);OnProductInfoReceived(infoData);}//产品列表请求失败public void ProductRequestFail(string message){OnProductInfoFail(message);}//购买成功回调public void ProductBuyComplete(string productId){OnProductBuyComplete(productId);}//购买失败回调public void ProductBuyFailed(string jsonData){var infoData = JsonConvert.DeserializeObject<BuyFailData>(jsonData);OnBuyProductFail(infoData.productId, infoData.error);}//获取商品回执回调public void ProvideContent(string msg) { }//购买取消回调public void ProductBuyCancled(string productId){OnBuyProductCancled(productId);}/// <summary>/// 恢复购买成功/// </summary>/// <param name="productId"></param>public void RestoreComplete(string productId){OnRestoreCompleted(productId);}public void ConnectTips(){Debug.LogWarning("Java Connect!");}public void ConnectTips1(string str){Debug.LogWarning($"Java Connect Test {str}!");}private void ClearCallback(){ProductBuyFailedCallback = null;ProductBuyCompleteCallback = null;ProductBuyCancledCallback = null;}#endregion//接收到产品信息void OnProductInfoReceived(IAPProductInfoData info){Debug.Log("[IAPMessage]Unity接收到商品信息:" + info.ToString());SDKGuanLiQi.SetInitShopState(true);}//接收到产品信息void OnProductInfoFail(string error){Debug.Log("[IAPMessage]Unity商品信息请求失败:" + error);SDKGuanLiQi.SetInitShopState(false);}//购买完成void OnProductBuyComplete(string productId){Debug.Log("[IAPMessage]购买完成" + productId);ProductBuyCompleteCallback?.Invoke();ClearCallback();}//购买失败void OnBuyProductFail(string productId, string error){Debug.Log(string.Format("[IAPMessage]购买失败:{0} 错误信息{1}", productId, error));ProductBuyFailedCallback?.Invoke();ClearCallback();}//购买取消void OnBuyProductCancled(string productId){Debug.Log("[IAPMessage]购买取消" + productId);ProductBuyCancledCallback?.Invoke();ClearCallback();}//恢复完成void OnRestoreCompleted(string productId){}}
Java代码:
package com.XXX.unitytogoolgleplaylib;// 与C#交互的接口
public interface IAPMessage
{//获取到产品列表回调public void RecieveProductInfos(String jsonData);//产品列表请求失败public void ProductRequestFail(String message);//购买成功回调public void ProductBuyComplete(String productId);//购买失败回调public void ProductBuyFailed(String jsonData);//获取商品回执回调public void ProvideContent(String msg);//购买取消回调public void ProductBuyCancled(String productId);/// <summary>/// 恢复购买成功/// </summary>/// <param name="productId"></param>public void RestoreComplete(String productId);
}
然后调用时赋值的方式参考图:


第一张图为Android Studio中的项目截图,第二张则是C#代码截图,演示一下的,没什么难度一试便会了,很简单
但需要注意的是接入的com.android.billingclient版本与JDK版本兼容性的问题,推荐接入6.0.1,因为本人接入的就是这个版本的,下面再附加上一张我的模块的build.gradle配置图

补档:第25行中的jar包实际上就是Unity的jar包,导入后可以通过import com.unity3d.player,直接使用UnityPlayer.UnitySendMessage方法,从而不用通过反射的方式去进行调用,该jar包的路径为:你的Unity安装路径\Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono\Release\Classes,
上方路径中的mono所在的位置中的il2cpp下相对于的位置也有一个jar包,这个jar包我没试过,有兴趣的可以试试。
注:因为考虑到兼容性的问题,所以对于插件的部分的指定的目标SDK我就设置为了32版本使用JDK进行构建,弄得太低了的话,担心在后期又要进行升级,就很麻烦,总之就是多一事不如少一事,总之具体设置为那个版本就看你的需求了
同时构建完成后jar包可在下图中的路径下边找到,就不用去解压aar包了,毕竟每次都去解压比较麻烦

这里补档说明一下, 因为是对支付模块的单独构建打包,在构建时可能会因为插件中所需要使用的其他插件的版本问题而导致构建失败,出现这些问题的时候,可以在下图中修改一下所使用的Gradle版本和其他模块的版本,修改为你构建时所需要的版本,同样的图中的内容仅作参考:

因为我使用的Android Studio版本是2024.2.1版本的,所以使用其他版本的配置方式可能存在一些细节上的不同
3、导出工程后再Android Studio中进行构建
这里是大头,因为这里边的坑才是最多的,导出的方法不做详细解释,只对使用Android Studio打开导出的项目包后的操作进行说明
1、修改Gradle版本
这里需要修改的为编译时使用的Gradle版本与Android Gradle 插件版本,修改编译时的Gradle版本路径如下图,直接修改配置文件中的版本号就好了,至于需要修改为那个版本,就需要查看Android Gradle插件版本所需要的版本了
修改Android Gradle插件版本,看下边截图了,也是直接修改版本号就行了:

修改Gradle方法(同时也是修改JDK、NDK的操作步骤之一)还有一个就是如下图,按照截图顺序操作修改为所需要的版本后应用一下就好了:

2、为build.gradle配置文件添加命名空间名称 namespace "com.XXX.XXX"
如下图,下图为unityLibary下的build.gradle配置文件添加命名空间,注意命名空间名称只能为namespace "com.unity3d.player",改成其他的都会出问题,然后记得删得NDK的配置路径,因为可能你所使用的插件所需的最低NDK版本比Unity所提供的NDK版本高,反正删了少一堆问题就对了,里边使用的JavaVersion版本也随手改一下,避免使用Android Studio修改Java 版本的时候,没有修改到的情况出现

删掉或者注释掉下图中框起来的部分可以加快打包的时间,之前百度优化包体时看到的其他的解释是,去掉再次进行il2cpp的编译过程还是什么的是,反正删掉了不影响编译结果,出现其他问题的话,再次加回来再次编译就行了

然后在其他的build.gradle文件中找到android {......}的内容块,并在android{.....}块中的第一行加入命名空间 namespace "这里修改为你的应用的包名",例如下图,包名可在下面第二张图中找到


3、修改JDK、NDK、Build Tools版本等
打开Project Structur窗口,操作步骤参考上方修改Gradle版本的第二个方法,然后根据下图中框选的部分,修改所需要的SDK、JDK、NDK、Build Tools等的版本后应用保存一下,如果没有所需要的版本的话,可以在File-》Settings打开Settings窗口后,看下边第二张图

没错就是这张图,注意如果要通过修改配置文件的方式配置修改Gradle版本版本的话,记得下图中的Distribution的配置就不要进行修改

然后SDK、NDK、Build Tools的安装看这张图,记得勾选右下角的show package details选项看到更多的内容

4、修改所有能找到的AndroidManifest.xml文件,注意是所有(主要是为了减小打包后的包体大小,不介意包体大小的可以不改)
在application后边加上android:extractNativeLibs="true"参考下图

如果已经存在android:extractNativeLibs配置并且为false,就修改为true,添加这段的具体原因则是为了启用压缩功能,详情自行百度,毕竟本人也不是做安卓开发的这段也只是搜索优化时偶然看到的
5、修改settings.gradle文件,如下图,非必要步骤

其实就是使用Unity原本的配置就好了,添加上这一步的主要原因是为了避免因为将maven仓库的源修改为使用国内镜像时,导致一些jar包下载搜索不到的问题,毕竟接入的是google的SDK,翻墙都没问题了,使用原本的配置也就不会出现对下载速度造成影响的问题了
结语
好了,恭喜你完成以上步骤后就可以同步一下然后进行apk的构建了,其中可能因为省略了一些步骤看着会比较迷茫,后期我不定时改改吧,因为连续加班也是弄得脑袋不舒服,详细步骤需要关注的点也可能少了一些,不过还是欢迎留言,看到了也都会第一时间进行回复的

最后2025年1月1日,元旦节快乐
祝大家都能拥有幸福开心满意的工作,并且每天都能不加班可以多陪陪家人
相关文章:
Unity2022接入Google广告与支付SDK、导出工程到Android Studio使用JDK17进行打包完整流程与过程中的相关错误及处理经验总结
注:因为本人也是第一次接入广告与支付SDK相关的操作,网上也查了很多教程,很多也都是只言片语或者缺少一些关键步骤的说明,导致本人也是花了很多时间与精力踩了很多的坑才搞定,发出来也是希望能帮助到其他人在遇到相似问…...
反向传播算法的偏置更新步骤
偏置的更新步骤 假设我们有一个三层神经网络(输入层、隐藏层和输出层),并且每层的激活函数为 sigmoid 函数。我们需要更新隐藏层和输出层的偏置。以下是详细的步骤: 1. 计算误差项(Error Term) 输出层的…...
条款47:请使用 traits classes 表现类型信息(Use traits classes for information about types)
条款47:请使用 traits classes 表现类型信息 1.1 提出问题 想一想,下面的功能如何实现?(可以查看std::advance源码) template<typename IterT, typename DistT> void advance(IterT& iter, DistT d); /…...
yolov5和yolov8的区别
1. yolov5有建议框,yolov8没有建议框 2. yolov5标签中有自信度,而yolov8没有自信度。因为自信度是建议框和真实框的交集 3. yolov5有三个损失函数,回归问题:预测框和建议框的损失(中心点宽高偏移量的损失):CIOUFocal…...
Redis 实现分布式锁
文章目录 引言一、Redis的两种原子操作1.1 Redis 的原子性1.2 单命令1.3 Lua 脚本1.4 对比单命令与 Lua 脚本 二、Redis 实现分布式锁2.1 分布式锁的概念与需求2.1.1 什么是分布式锁?2.1.2 分布式锁的常见应用场景 2.2 基于 Redis 的分布式锁实现2.2.1 锁的获取与释…...
django StreamingHttpResponse fetchEventSource实现前后端流试返回数据并接收数据的完整详细过程
django后端环境介绍: Python 3.10.14 pip install django-cors-headers4.4.0 Django5.0.6 django-cors-headers4.4.0 djangorestframework3.15.2 -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple 总环境如下: Package Version -…...
SpringSpringBoot常用注解总结
目录 1. SpringBootApplication 2. Spring Bean 相关 2.1. Autowired 2.2. Component,Repository,Service, Controller 2.3. RestController 2.4. Scope 2.5. Configuration 3. 处理常见的 HTTP 请求类型 3.1. GET 请求 3.2. POST 请求 3.3. PUT 请求 3.4. DELETE 请…...
24.小R的随机播放顺序<字节青训营-中等题>
1.题目 问题描述 小R有一个特殊的随机播放规则。他首先播放歌单中的第一首歌,播放后将其从歌单中移除。如果歌单中还有歌曲,则会将当前第一首歌移到最后一首。这个过程会一直重复,直到歌单中没有任何歌曲。 例如,给定歌单 [5, …...
【QT】增删改查 XML 文件的类
使用单例类模板实现的对XML文件的节点、属性、文本进行增删改查,可以直接用! 直接POST代码,比较简单好用。 针对以下格式的xml文件比较适用 每个节点的名称都不一样,节点包含了各种属性。 <?xml version="1.0" encoding="UTF-8"?> <config…...
Linux-掉电保护方案
参考链接 https://blog.csdn.net/pwl999/article/details/109411919硬件设计 设备树 驱动程序 #include <linux/module.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/gpio.h>int irq;//中断服务函数 irqreturn_t tes…...
php获取字符串中的汉字
在PHP中,可以使用正则表达式来提取字符串中的汉字。汉字通常位于Unicode范围\u4e00-\u9fa5之内,因此可以使用preg_match_all函数配合适当的正则表达式来实现。 以下是一个PHP代码示例,它会从给定的字符串中提取出所有的汉字: fu…...
java: JDK isn‘t specified for module ‘product-service‘问题解决
目录 问题 解决方法 1.打开File->Project Structure... 2.将Project SDK修改为17 Oracle OpenJDK 17.0.12,并Apply,OK 问题 添加module后报错:java: JDK isnt specified for module product-service 查看pom.xml文件也添加了对应的JDK…...
使用工厂+策略模式实现去除繁琐的if else
使用工厂策略模式实现去除繁琐的if else 在中间有一个mapstruct的bug,即在修改实体类中的类型时,或者修改属性名字,mapstruct都无法进行转换,会报错,此时需要maven cleanmaven compile即可 前言 在这次的开发中&#…...
Dubbo3入门项目搭建
开发环境:jdk8、dubbo3.2.9、nacos2.3.0、springboot2.7.17、dubbo-admin0.6.0。 Dubbo 是一个高性能的 Java RPC(远程调用)框架,最初由阿里巴巴开发并开源,主要用于构建 SOA 架构下的分布式应用系统( soa简单理解就是…...
形象地理解UE4中的数据结构 TLinkedListBase
大家都熟知链表,但不一定能快速看懂UE4中的数据结构。 TLinkedListBase表示“链接”中的一个结点,有三个成员: 一、ElementType Element; 表示具体的业务,例如int链条中的一个整数。 二、NextLink 表示 “下一个Node”&#…...
Python自然语言处理利器:SnowNLP模块深度解析、安装指南与实战案例
Python自然语言处理之SnowNLP模块介绍、安装与常见操作案例 一、SnowNLP模块介绍 SnowNLP是一个专为中文文本设计的Python库,它基于自然语言处理技术,提供了多种功能,包括分词、词性标注、情感分析、文本转换(简繁转换ÿ…...
Llama系列关键知识总结
系列文章目录 第一章:LoRA微调系列笔记 第二章:Llama系列关键知识总结 第三章:LLaVA模型讲解与总结 文章目录 系列文章目录Llama: Open and Efficient Foundation Language Models关键要点LLaMa模型架构:Llama2分组查询注意力 (G…...
【开源】创建自动签到系统—QD框架
1. 介绍 QD是一个 基于 HAR 编辑器和 Tornado 服务端的 HTTP 定时任务自动执行 Web 框架。 主要通过抓包获取到HAR来制作任务模板,从而实现异步响应和发起HTTP请求 2. 需要环境 2.1 硬件需求 CPU:至少1核 内存:推荐 ≥ 1G 硬盘:推…...
CDP集群安全指南系列文章导读
[一]大数据安全综述 1-认证 身份验证是任何计算环境的基本安全要求。简单来说,用户和服务必须在使用系统功能并获得授权之前,向系统证明其身份(进行身份验证)。身份验证与授权紧密配合,共同保护系统资源。大多数 CDH …...
MT8788安卓核心板_MTK8788核心板参数_联发科模块定制开发
MT8788安卓核心板是一款尺寸为52.5mm x 38.5mm x 2.95mm的高集成度电路板,专为各种智能设备应用而设计。该板卡整合了处理器、图形处理单元(GPU)、LPDDR3内存、eMMC存储及电源管理模块,具备出色的性能与低功耗特性。 这款核心板搭载了联发科的MT8788处理…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...
Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...
8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...
SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
重启Eureka集群中的节点,对已经注册的服务有什么影响
先看答案,如果正确地操作,重启Eureka集群中的节点,对已经注册的服务影响非常小,甚至可以做到无感知。 但如果操作不当,可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...
