IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android .obb 详解 -> 正文阅读

[移动开发]Android .obb 详解

1.简介

在Android APP Bundle(aab)之前,上架Google Play 项目都是打包成APK上传,但是Google 对 APK大小是有限制的,刚开始是50M,后来扩展到100M,但是有些APK资源比较多,可能会大于100M, 基于这种情况,Google 允许上传一个额外的扩展文件,这个文件就是咱们今天要详解的.obb文件。每当您使用 Google Play 管理中心上传 APK 时,您都可以选择向 APK 添加一个或两个扩展文件。每个文件的大小上限为 2 GB,文件格式可以是您选择的任意格式。不过,为了节约下载时的带宽,我们建议您使用压缩格式的文件。从概念上讲,每个扩展文件扮演着不同的角色:

  • 扩展文件是应用必需的额外资源所在的主要扩展文件。
  • 补丁扩展文件是可选的,用于为主扩展文件提供小规模的更新。

尽管您可以按照您需要的方式使用这两个扩展文件,但我们建议您按如下方式使用:主扩展文件提供主要的资源,尽量不要更新;补丁扩展文件应该比较小,用作“补丁载体”,在每次发布重要版本时或根据需要进行更新。

不过,即使应用更新只需要新的补丁扩展文件,您仍然必须上传新的 APK 并在清单中更新?versionCode。(Play 管理中心不允许您将扩展文件上传到现有 APK 中。)

2.生成.obb

一般我们会把APP中一些大的资源,或者升级用的APK,先打包成一个zip, 比如名字为:MYOBB.zip? ?然后再对打包成的ZIP重命名成: main.versionCode.包名.obb? ?比如: main.22070479.cool.obb.android.obb

3.随着APK 一块把obb文件上传到Google Play Console:

打开Google Console后台,找到对应的项目:??https://play.google.com/console/u/0/developers

上传APK??

?

?上传完APK后? 有个更多 点击更多,选择上传扩展文件(.obb)

?

?

?

?

?就这样把APK和obb文件一块上传到Google Play,内测用户就可以下载安装了,等测试的没问题就可以发布到正式线上环境了,当用户下载该APK时,我们上传的obb文件也会同步下载到手机中

4.下载APK的同时下载对应的obb文件

下载APK后 ,之前上传的obb文件也会同步下载下来,当 Google Play 将扩展文件下载到设备时,会将其保存到系统的共享存储位置。为确保应用的正常运行,请勿删除、移动或重命名扩展文件。如果您的应用必须自行从 Google Play 进行下载,那么您必须将文件保存到相同的位置。

下载下来后存放的位置:

根目录:getExternalStorageDirectory()?+ /Android/obb/<package-name>/XXX.obb

例如:

        String obb_filename = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/obb/" + getPackageName() + "/main.22070479.cool.obb.android.obb";

?这个时候打开APP后就开始解压使用obb文件了

5.解压并使用OBB中的文件:

首先APP要有读写权限才能对obb文件操作:

 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

拿到读写权限后开始解压obb:

   public void unZipObb(String srcFilePath, String dstFolderPath) {
        Log.d("MainActivity", "unZipObb : srcFilePath=" + srcFilePath + ", dstFolderPath=" + dstFolderPath);
        try {
            String obbFilePath = srcFilePath;
            if (obbFilePath == null) {
                Log.d("MainActivity", "unZipObb error : obbFilePath == null");
                return;
            } else {
                File obbFile = new File(obbFilePath);
                if (!obbFile.exists()) {
                    //下载obb文件
                    Log.d("MainActivity", "unZipObb error : !obbFile.exists()");
                } else {
                    File outputFolder = new File(dstFolderPath);
                    if (!outputFolder.exists()) {
                        //目录未创建 没有解压过
                        outputFolder.mkdirs();
                        unZip(obbFile, outputFolder.getAbsolutePath());
                    } else {
                        //目录已创建 判断是否解压过
                        if (outputFolder.listFiles() == null) {
                            //解压过的文件被删除
                            unZip(obbFile, outputFolder.getAbsolutePath());
                        } else {
                            //此处可添加文件对比逻辑
                            Log.d("MainActivity", "unZipObb error : outputFolder.listFiles() != null");
                        }
                    }
                }
            }
        } catch (Exception e) {
            Log.d("MainActivity", "unZipObb error : Exception");
            e.printStackTrace();
        }
    }

    public void createDirectoryIfNeeded(String folderPath) {
        File folder = new File(folderPath);
        if (!folder.exists() || !folder.isDirectory()) {
            folder.mkdirs();
        }
    }

    public void unZip(File zipFile, String outPathString) {
        Log.d("MainActivity", "unZip " + zipFile.getName() + " to " + outPathString);
        try {
            createDirectoryIfNeeded(outPathString);
            ZipInputStream inZip = new ZipInputStream(new FileInputStream(zipFile));
            ZipEntry zipEntry;
            String szName;
            while ((zipEntry = inZip.getNextEntry()) != null) {
                szName = zipEntry.getName();
                if (zipEntry.isDirectory()) {
                    szName = szName.substring(0, szName.length() - 1);
                    File folder = new File(outPathString + File.separator + szName);
                    folder.mkdirs();
                } else {
                    File file = new File(outPathString + File.separator + szName);
                    createDirectoryIfNeeded(file.getParent());
                    file.createNewFile();
                    FileOutputStream out = new FileOutputStream(file);
                    int len;
                    byte[] buffer = new byte[1024];
                    while ((len = inZip.read(buffer)) != -1) {
                        out.write(buffer, 0, len);
                        out.flush();
                    }
                    out.close();
                }
            }
            inZip.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

6.拿到OBB中的文件,就可以使用解压出来的文件了:

    String srcPNG1 = Environment.getExternalStorageDirectory().getAbsolutePath() + "/WhOOB/MYOBB/11.png";
        String srcPNG2 = Environment.getExternalStorageDirectory().getAbsolutePath() + "/WhOOB/MYOBB/12.png";
        String srcPNG3 = Environment.getExternalStorageDirectory().getAbsolutePath() + "/WhOOB/MYOBB/13.png";
        String srcPNG4 = Environment.getExternalStorageDirectory().getAbsolutePath() + "/WhOOB/MYOBB/14.png";

        mChangeBTN.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                int position = mCount % 4;
                switch (position) {
                    case 0:
                        Glide.with(MainActivity.this).load(srcPNG1).into(mShowImageView);
                        break;
                    case 1:
                        Glide.with(MainActivity.this).load(srcPNG2).into(mShowImageView);
                        break;
                    case 2:
                        Glide.with(MainActivity.this).load(srcPNG3).into(mShowImageView);
                        break;
                    case 3:
                        Glide.with(MainActivity.this).load(srcPNG4).into(mShowImageView);
                        break;
                }
                mCount++;

            }
        });

总结:详细介绍了OBB的整个生命周期,从生成OBB----->上传Google Play ---->用户下载同步OBB ----->解压OBB ----->使用OBB中的文件

参考文档:https://developer.android.com/google/play/expansion-files#Overview

?OBB Demo? GitHub :?https://github.com/JasonZhangHG/OBBDemo.git

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-12-25 11:21:31  更:2022-12-25 11:25:02 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/25 2:46:16-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计