PAD 踩坑记录

news/2025/1/12 23:44:06/

文章目录

      • 背景
      • 1. 工程里配置PAD
      • 2. 调试
        • bundletool
        • 上传到 google play
        • 参考代码
      • 3.踩过的坑
        • Unity 读取不到资源
        • 手动创建 assets pack 包?

背景

Google 提供了 PAD (Play Asset Delivery) 的能力,能够支持将一个应用拆分成多份,这样用户就可以按需下载。

PAD 支持三种分发模式,具体如下:

分发模式备注
install-time用户安装的时候就会下载,和 apk 内的 assets 目录下的资源使用方式一致
fast-follow在用户安装完应用之后会自动下载
on-demand只有在需要的场景才会下载

我们的应用分成两个工程,一个是 Unity 工程,会将各种资源打包成 bundle 包,另外一个是 android 工程,引用 Unity 打包出来的各种资源。

对于我们的应用场景来说,只需要 install-time 和 on-demand 方式,把必须的一些 bundle 包设置成 install-time 的方式,用户安装完 app,就能直接使用,
而对于非必须的 bundle 包则设置成 on-demand,进入到特定的场景之后再动态去下载。

1. 工程里配置PAD

在 Android 里面引入 PAD 相对来说比较简单,按照官文档一步一步操作就可以了。

官方文档:https://developer.android.com/guide/playcore/asset-delivery/integrate-java?hl=zh-cn

配置成功之后,执行以下命令就能够生成 aab 包

./gradlew bundleDebug
或者
./gradlew bundleRelease

在这里插入图片描述

2. 调试

生成出来的 aab 包不能直接安装到手机上,需要借助 bundletool 工具调试或者将其上传到 google play 上。

bundletool

地址:https://github.com/google/bundletool/releases

将 aab 包和 bundletool 放到一个文件夹下,执行以下指令,该指令会自动将 aab 包安装到手机上。


java -jar bundletool-all-1.11.2.jar build-apks --bundle=Application-debug.aab --output=app.apks 
java -jar bundletool-all-1.11.2.jar install-apks --apks=app.apks

在这里插入图片描述
但是以这种方式安装只能调试 install-time 类型的包,对于 on-demand 方式的包,只能上传到 google play 上进行调试。

所以在前期调试包内的逻辑时,可以先将包类型全部设置成 install-time,包内逻辑调试完成之后,再设置成 on-demand 类型。

上传到 google play

我们可以先创建内部测试版本,然后将自己的 google 账号添加到内部测试人员当中,然后就可以通过 google play 进行下载测试了。
在这里插入图片描述

上传完成之后可以清晰的看到每一个 asset pack 的类型和大小。
在这里插入图片描述

参考代码

Android 当中获取 install-time 类型的资源,和获取普通的 assets 目录下的资源方式一样

fun getInstallTimeAssetBundle(context: Context, assetPackName:String) {GlobalScope.launch(Dispatchers.IO) {try {QLog.i(TAG,QLog.USR,"开始获取installTime "+assetPackName)val assetManager: AssetManager = context.assetsval list = assetManager.list("assetpack")QLog.i(TAG,QLog.USR,"list:"+list)list?.forEach {QLog.i(TAG,QLog.USR,"fileName:"+it)}val stream: InputStream = assetManager.open(assetPackName)val byteOutputStream:ByteArrayOutputStream = ByteArrayOutputStream()val byte = ByteArray(1024)var length = 0while (stream.read(byte)>0){byteOutputStream.write(byte)}QLog.i(TAG,QLog.USR,"获取结束"+assetPackName+",length="+byteOutputStream.size())} catch (e: Exception) {QLog.e(TAG, QLog.USR, "getAssetBundle error $assetPackName:" + e)}}
}

Android 当中获取 on-demand 类型的资源


fun getOnDemandAssetBundle(context: Context,assetPackName: String){GlobalScope.launch(Dispatchers.IO) {try {QLog.i(TAG, QLog.USR, "开始获取ondemand:" + assetPackName)val manager: AssetPackManager =AssetPackManagerFactory.getInstance(context.applicationContext)QLog.i(TAG, QLog.USR, "注册监听:" + assetPackName)manager.registerListener { assetpackState ->QLog.i(TAG,QLog.USR,"status:"+assetpackState.status()+",name:"+assetpackState.name())}QLog.i(TAG, QLog.USR, "开始fetch:" + assetPackName)val assetsate = manager.requestFetch(listOf(assetPackName))QLog.i(TAG,QLog.USR,"返回的state: length:"+assetsate.totalBytes()+",status:"+assetsate.packStates)} catch (e: Exception) {QLog.e(TAG, QLog.USR, "getOnDemandAssetBundle error $assetPackName:" + e)}}
}

Unity 当中读取 bundle 资源,这里有个坑,就是 Unity 读取的资源必须要求 asset pack 包和 bundle 包必须是相同的名称,否则就读取不到,而 Android 当中只要把路径和 bundle 名称写进去就能够读到了。

PlayAssetDelivery.RetrieveAssetBundleAsync(assetBundleName);

3.踩过的坑

Unity 读取不到资源

最初,我的设想是创建两个包,一个是 install-time,一个是 on-demand。这样我们只需要把对应类型的 bundle 放到这两个包内就可以了。
在这里插入图片描述
但是,实际测试在 Unity 里面死活读不到资源,但是在 Android 工程里面又可以读取到。

没办法只能去看 Unity 相关的 API,我们在注释里面找到了下面这一句,asset pack包和 bundle 必须要保持相同的名称!
在这里插入图片描述
于是我们又做创建了一个 common 包用于测试,果然能够读取到了。
在这里插入图片描述

手动创建 assets pack 包?

Unity 能够读取到 bundle 资源了,但是这样又带来了另外一个问题,那就是需要创建好多个包,而且每次 Unity 工程增加一个 bundle 包,那么在 Android 工程里面就得增加一个对应的 asset pack 包。

手动创建肯定不太现实,会麻烦死的,那是不是可以通过脚本来实现呢?

仔细观察,发现每个 asset pack 包其实结构相对固定,只是内容不同,因此完全有可能通过脚本来动态的创建 asset pack 包。
在这里插入图片描述
具体脚本如下:

WORKSPACE=****
projectPath=$WORKSPACEparentName=padModules#解压文件
unzipPad() {cd padecho -e "\n"echo "> unzip pad start"if [ -d "installTime_path/" ]; thenrm -r installTime_path/fiif [ -d "onDemand_path/" ]; thenrm -r onDemand_path/fiif [ -d "AssetBundles/" ]; thenrm -r AssetBundles/fiunzip -oq installTime.zip -d installTime_path/unzip -oq onDemand.zip -d onDemand_path/unzip -oq AssetBundles.zip -d AssetBundles/echo "- unzip pad end "echo -e "\n"
}#将ab包copy到assets目录
packIn() {assets_path=$WORKSPACE/xxx/src/main/assetscp -rf AssetBundles/. $assets_path
}#将不同的ab包创建成不同的模块
packModules() {gradlereplace='assetPacks = ['# on_demandpath=onDemand_path/files=$(ls $path)for filename in $filesdogradlereplace="$gradlereplace \":$parentName:$filename\" ,"buildModule $filename on-demand $path/$filenamedone# install_timepath=installTime_path/files=$(ls $path)for filename in $filesdogradlereplace="$gradlereplace \":$parentName:$filename\" ,"buildModule $filename install-time $path/$filenamedonegradlereplace=`echo ${gradlereplace%?}`gradlereplace="$gradlereplace ]"echo $gradlereplaceecho "在Application的build.gradle里面添加模块"gradle=$projectPath/Application/build.gradletobeReplace="assetPacks = \[\]"sed -i "s/$tobeReplace/$gradlereplace/" $gradle
}#传递参数为模块名,类型[install-time或者on-demand],assetpack路径
buildModule() {moduleName=$1type=$2filePath=$3echo "开始创建:模块名$moduleName 类型 $type"echo "1.复制assetpack:模块名$moduleName"modulePath=$projectPath/$parentName/$moduleNameassetsPath=$modulePath/src/main/assets/assetpackscriptFile=$modulePath/build.gradle.ktsif [ -d $modulePath ]; thenrm -r $modulePathfimkdir -p $modulePathmkdir -p $assetsPathcp -rf $filePath $assetsPathecho "2.创建buildgradle文件:模块名$moduleName "cat>$scriptFile<<EOF
plugins {id("com.android.asset-pack")
}assetPack {packName.set("$moduleName")dynamicDelivery {deliveryType.set("$type")}
}
EOFecho "3.在settings.gradle里面添加:模块名$moduleName "settings=$projectPath/settings.gradleinclude=:$parentName:$moduleNameif [ `grep -c "$include" $settings` -ne '0' ];thenecho has $includeelsecat>>$settings<<EOF
include '$include'
EOFfi
}cd $WORKSPACEunzipPad
packModules

参考文档:

https://developer.android.com/guide/playcore/asset-delivery/integrate-java?hl=zh-cn


http://www.ppmy.cn/news/378459.html

相关文章

new pad不能用usb充电的解决方法

今天玩了一下new pad &#xff0c;但是把充电器忘在公司啦。。。用iPhone的线插在电脑上&#xff0c;出现"不在充电"&#xff0c;很是苦闷&#xff1b;google了问题&#xff0c;说是new pad的插座式5.1v&#xff0c;usb输入时5v blablabla之类的。 但是我发现我的三…

deepstream 2D 3D 动作识别(包括file、rtsp输入输出)

deepstream 2D 3D 动作识别&#xff08;包括file、rtsp输入输出&#xff09; deepstream c/c 在nvidia官方deepstream-3d-action-recognition的基础上进行修改&#xff0c;增加多类sink的输出 参考&#xff1a;基于deepstream-test3添加跟踪插件和4类sinkType输出&#xff08…

2022-9-19

//main.c #include<stdio.h> #include<stdlib.h> #include"head.h" int main(int argc,const char *argv[]) {LinkList L create();if(NULL L){printf("create失败\n");return -1;}int num;printf("请输入一个整数&#xff1a;");…

2022/12/9

1【CTF学习】Python安全编程与Python运维实战 2 洛谷

2022-9-2

第一题 && 第二题 #include <stdio.h> #define N 50 int main(){char a[50];int num 0,flag;printf("请输入:");gets(a);puts(a);for(int i 0;i < N - 1;i){if(a[i] ){num;}if(a[i] \0){flag i;break;}};printf("空格个数:%d\n",…

2022-9-1

第一题 #include <stdio.h> int main(){float score[6],t;printf("请输入6名学生成绩:");for(int i 0;i < 6;i){scanf("%f",score i);}for(int i 1;i < 6;i){for(int j 0;j < 6 - i;j){if( score[j] > score[j1] ){t score[j];sc…

2021/9/29

找到变量环境 01打开系统属性 02打开左侧高级设置。 03点击打开环境变量&#xff0c;进入界面。 04找出界面窗口即可对环境变量进行设置。 Java开发工具有哪些 java开发工具有JBuilder、VisualAgeforJava、ForteforJava,VisualCafe、 Eclipse、NetBeansIDE、JCreatorJ2SDK、jdk…