使用谷歌范围内存储API在本地C/C++代码中访问文件的安卓系统

 2023-01-21    278  

问题描述

我需要在本机C/C ++代码中的Android应用中通过文件名打开文件.本机代码是我不想修改的第三方库,但是它们通常需要文件名作为参数才能读取/写文件.借助Google的”范围存储” API并禁用Android 10或更高版本中文件的本机访问,这是一个真正的问题.

一个众所周知的解决方案是获取文件描述符并使用” proc/self/fd/fd_numer”技巧,例如:

使用谷歌范围内存储API在本地C/C++代码中访问文件的安卓系统

ParcelFileDescriptor mParcelFileDescriptor = null;

       String getFileNameThatICanUseInNativeCode(Context context, DocumentFile doc) { 
           try {
                Uri uri = doc.getUri();
                mParcelFileDescriptor =
                        context.getContentResolver().openFileDescriptor(uri, "r");
                if (mParcelFileDescriptor != null) {
                    int fd = mParcelFileDescriptor.getFd();
                    return "/proc/self/fd/" + fd;
                }
            }
            catch (FileNotFoundException fne) {
                return "";
            }
        }

        // Don't forget to close mParcelFileDescriptor when done!

将其传递给本机C/C ++代码有效,但是仅当文件在手机主存储中时.如果用户试图打开插入手机插槽中外部SD卡上的文件,则该文件无效 – 没有此方式打开文件的读取权限.我只能抓住文件描述符int编号并使用FDOPEN(FD).但这将需要修改第三方库(开源或许可)的源代码,并且每当这些库的原始源被更新时.

>

有更好的解决方案解决该问题吗?不,我不想听到添加

的解决方案

android:requestLegacyExternalStorage="true"

到AndroidManifest.xml应用程序部分 – Google威胁要禁用在2020年的下一个Android中,因此需要永久解决方案.另一个简单但愚蠢的解决方案是将用户试图打开的整个(也许是巨大)文件复制到私有应用程序目录中.愚蠢而无用…

推荐答案

2020年5月19日更新:刚发现:read_external_storage许可使您可以读取文件,但在Android 11上运行并定位API 30(或将来更高)(或将来更高).我将其作为错误提交,然后刚刚得到”这是按预期工作”的回复( https://issuetracker.google .com/essugy/156660903 ).如果有人在乎,请在那里发表评论,以及他们的”调查”: https ://google.qualtrics.com/jfe/form/sv_9hozzyeciew0ij3?source = scoped-storage 我不知道如何使用所有这些限制在Android上开发应用程序.

更新2020年5月17日:Google终于承认了,并允许Android 11及以后的Read_External_storage许可.在将我的应用程序转换为存储访问框架(SAF)之后,我现在花一两个星期将其转换回它,至少将读取文件部分转换为常规文件访问…谢谢您,Google!讽刺地感谢您的时间和精力,并真诚地感谢您,至少部分理解了我们的观点!

因此,我以前列出的以前的答案不再需要,请叹息!

在Android的”范围存储” B.S.浪费了我一生中的又一个美好的一天之后,我找到了一种有效的解决方案,而没有修改第三方本地图书馆的来源,但只要一个人具有这些库的来源,并且可以构建它们.

我的(非常不令人满意的)解决方案是:将以下选项添加到C/C ++编译命令:

-include "[some/path/]idiocy_fopen_fd.h"

和idiocy_fopen_fd.h如下所示,如您所见,iDiocy_fopen_fd()代码替换了对常规fopen()的每个调用,该代码检查文件名是否以”/proc/proc/self/fd/”开头. ,如果是这样,请提取文件描述符编号并调用fdopen()而不是fopen()…如果某人有更好的解决方案,最好当您没有第三方libs的源代码时也可以使用.请分享.

#ifndef fopen_fd

#include <stdio.h>
#include <string.h>
#include <unistd.h> // for dup()

#ifdef __cplusplus
extern "C" {
#endif

inline FILE* idiocy_fopen_fd(const char* fname, const char * mode) {
  if (strstr(fname, "/proc/self/fd/") == fname) {
    int fd = atoi(fname + 14);
    if (fd != 0) {
      // Why dup(fd) below: if we called fdopen() on the
      // original fd value, and the native code closes
      // and tries re-open that file, the second fdopen(fd)
      // would fail, return NULL - after closing the
      // original fd received from Android, it's no longer valid.
      FILE *fp = fdopen(dup(fd), mode);
      // Why rewind(fp): if the native code closes and 
      // opens again the file, the file read/write position
      // would not change, because with dup(fd) it's still
      // the same file...
      rewind(fp);
      return fp;
    }
  }
  return fopen(fname, mode);
}
// Note that the above leaves the original file descriptor
// opened when finished - close parcelFileDescriptor in
// Java/Kotlin when your native code returns!

#ifdef __cplusplus
}
#endif

#define fopen idiocy_fopen_fd

#endif

其他推荐答案

嗨@gregko我设法获得了真实的路径,而不是FD路径,并将其发送到我的本地活动,这减轻了负担

String getFileNameThatICanUseInNativeCode(Uri uri) throws FileNotFoundException {
      mParcelFileDescriptor =
              getApplicationContext().getContentResolver().openFileDescriptor(uri, "r");
      if (mParcelFileDescriptor != null) {
        int fd = mParcelFileDescriptor.getFd();
        File file = new File("/proc/self/fd/" + fd);
        String path = null;
        try {
          if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            path = Os.readlink(file.getAbsolutePath()).toString();
          }
        } catch (ErrnoException e) {
          e.printStackTrace();
        }

        return path;
      }
      else{
        return null;
      }
  }

使用此代码,我基本上做了一个完整的循环,然后我得到/storage/cc12-ff343/games/game.zip而不是/proc/.. p>>

以上所述是小编给大家介绍的使用谷歌范围内存储API在本地C/C++代码中访问文件的安卓系统,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对77isp云服务器技术网的支持!

原文链接:https://77isp.com/post/26272.html

=========================================

https://77isp.com/ 为 “云服务器技术网” 唯一官方服务平台,请勿相信其他任何渠道。