You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在ARCore中从本地存储运行时导入并渲染SFB文件?

解决ARCore加载本地存储SFB模型的问题

我来帮你搞定这个在ARCore里加载本地Download文件夹中SFB模型的问题~首先先梳理下你代码里的几个小问题,然后给出修正后的方案:

原代码的核心问题

  1. File路径格式错误:你给File构造器传了带file://前缀的路径,但File需要的是本地文件系统的绝对路径字符串(比如/storage/emulated/0/Download/andy.sfb),带file://的是Uri格式,会导致文件找不到。
  2. 不必要的线程操作:你用FutureTask单独开线程获取InputStream其实没必要,因为ModelRenderable.build()本身就是异步执行的,会在后台线程处理流加载逻辑。

修正后的完整代码

首先要确保你的应用已经获取了外部存储读取权限:

  • 在AndroidManifest.xml中添加权限声明:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  • Android 6.0及以上系统,需要动态申请权限,确保用户授权后再执行模型加载逻辑。

然后是加载模型的代码:

// 获取Download文件夹下的andy.sfb文件,用系统API更稳妥
File modelFile = new File(
    Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
    "andy.sfb"
);

ModelRenderable.builder()
    .setSource(this, () -> {
        try {
            // 直接返回文件输入流,ModelRenderable会在后台处理
            return new FileInputStream(modelFile);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            throw new RuntimeException("未找到目标模型文件", e);
        }
    })
    .build()
    .thenAccept(renderable -> {
        andyRenderable = renderable;
        // 这里可以添加模型加载成功后的逻辑,比如绑定到AnchorNode上
        Log.d("ModelLoad", "Andy模型加载成功");
    })
    .exceptionally(throwable -> {
        Log.e("ModelLoad", "模型加载失败", throwable);
        Toast toast = Toast.makeText(
            this,
            "加载Andy模型失败:" + throwable.getMessage(),
            Toast.LENGTH_LONG
        );
        toast.setGravity(Gravity.CENTER, 0, 0);
        toast.show();
        return null;
    });

针对Android 10+分区存储的补充说明

如果你的应用目标SDK版本是30及以上,直接用File访问外部存储可能会受到分区存储的限制,这时候可以通过MediaStore查询Download文件夹中的文件Uri,再通过ContentResolver获取输入流:

// 示例:通过MediaStore获取Download文件夹中andy.sfb的Uri
Uri modelUri = null;
String[] projection = {MediaStore.Files.FileColumns._ID};
String selection = MediaStore.Files.FileColumns.DISPLAY_NAME + " = ?";
String[] selectionArgs = {"andy.sfb"};

Cursor cursor = getContentResolver().query(
    MediaStore.Downloads.EXTERNAL_CONTENT_URI,
    projection,
    selection,
    selectionArgs,
    null
);

if (cursor != null && cursor.moveToFirst()) {
    long id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns._ID));
    modelUri = ContentUris.withAppendedId(MediaStore.Downloads.EXTERNAL_CONTENT_URI, id);
    cursor.close();
}

if (modelUri != null) {
    ModelRenderable.builder()
        .setSource(this, modelUri)
        .build()
        .thenAccept(renderable -> {
            andyRenderable = renderable;
            Log.d("ModelLoad", "通过Uri加载模型成功");
        })
        .exceptionally(throwable -> {
            // 异常处理逻辑
            return null;
        });
}

这种方式更符合Android 10+的存储规范,避免出现文件访问权限问题。

内容的提问来源于stack exchange,提问作者Jonas Kgomo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 05:36:39