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

FireMonkey在Android下通过Intent接收图片:如何访问图片URI?

Android下通过Content URI访问Intent传递的图片

你遇到的问题核心是:content://开头的URI是Content Provider访问标识,不是本地文件系统的物理路径,所以fileexists函数无法识别它。不能直接把URI当作文件路径使用,得通过Android的ContentResolver来访问对应的图片内容。

下面给两种可行的处理方案:

方案一:直接通过输入流加载图片(推荐,无需转路径)

直接利用Android的ContentResolver获取图片的输入流,再加载到Delphi的Bitmap中,无需转换物理路径,步骤如下:

修改你的HandleIntentAction函数:

function TForm1.HandleIntentAction(const Data: JIntent): Boolean;
var
  mytype  : STRING;
  imageUri: Jnet_Uri;
  ContentResolver: JContentResolver;
  InputStream: JInputStream;
  DelphiStream: TStream;
begin
  Result := False;
  if Data <> nil then
  begin
    Memo1.ClearContent;
    mytype := JStringToString(Data.getType);
    memo1.Lines.Add('Intenttype: '+mytype);
    if mytype.StartsWith('image/') then
    begin
      Memo1.Lines.Append('is image');
      imageUri := Data.getData;
      Memo1.Lines.Append('URI: '+JStringToString(imageUri.toString));

      // 获取ContentResolver实例
      ContentResolver := SharedActivity.getContentResolver;
      try
        // 打开URI对应的输入流
        InputStream := ContentResolver.openInputStream(imageUri);
        if Assigned(InputStream) then
        begin
          try
            // 将Java输入流转为Delphi流
            DelphiStream := TJavaInputStreamAdapter.Create(InputStream);
            try
              // 加载图片到Bitmap
              Image1.Bitmap.LoadFromStream(DelphiStream);
              Memo1.Lines.Append('图片加载成功');
              Result := True;
            finally
              DelphiStream.Free;
            end;
          finally
            InputStream.close;
          end;
        end
        else
          Memo1.Lines.Append('无法打开图片输入流');
      except
        on E: Exception do
          Memo1.Lines.Append('加载失败:' + E.Message);
      end;
    end;
    Invalidate;
  end;
end;

关键说明:

  • SharedActivity.getContentResolver:获取当前应用的ContentResolver,用于访问Content Provider提供的内容
  • openInputStream(imageUri):通过URI打开对应的输入流,这是访问Content URI内容的标准方式
  • TJavaInputStreamAdapter:把Java的InputStream转换成Delphi能识别的TStream,方便Bitmap加载

方案二:将图片复制到应用私有目录后访问(需保存文件时用)

如果需要把图片保存到本地再使用,可以将URI对应的内容复制到应用的私有目录(比如getFilesDir或getExternalFilesDir),之后就能用文件路径访问了:

function TForm1.CopyUriToPrivateFile(const Uri: Jnet_Uri): string;
var
  ContentResolver: JContentResolver;
  InputStream: JInputStream;
  OutputStream: JOutputStream;
  FilePath: string;
  JavaFile: JFile;
  Buffer: TBytes;
  ReadCount: Integer;
begin
  Result := '';
  ContentResolver := SharedActivity.getContentResolver;
  try
    InputStream := ContentResolver.openInputStream(Uri);
    if not Assigned(InputStream) then Exit;

    // 创建应用私有目录下的目标文件
    JavaFile := TJFile.JavaClass.init(SharedActivity.getFilesDir, 'received_image.jpg');
    FilePath := JStringToString(JavaFile.getAbsolutePath);
    OutputStream := TJFileOutputStream.JavaClass.init(JavaFile);

    try
      SetLength(Buffer, 8192);
      repeat
        ReadCount := InputStream.read(TJavaArray<Byte>.Create(Buffer), 0, Length(Buffer));
        if ReadCount <= 0 then Break;
        OutputStream.write(TJavaArray<Byte>.Create(Buffer), 0, ReadCount);
      until False;
      Result := FilePath;
    finally
      OutputStream.close;
      InputStream.close;
    end;
  except
    on E: Exception do
      Memo1.Lines.Append('复制文件失败:' + E.Message);
  end;
end;

// 在HandleIntentAction中调用该函数
function TForm1.HandleIntentAction(const Data: JIntent): Boolean;
var
  mytype  : STRING;
  imageUri: Jnet_Uri;
  LocalFilePath: string;
begin
  Result := False;
  if Data <> nil then
  begin
    Memo1.ClearContent;
    mytype := JStringToString(Data.getType);
    memo1.Lines.Add('Intenttype: '+mytype);
    if mytype.StartsWith('image/') then
    begin
      Memo1.Lines.Append('is image');
      imageUri := Data.getData;
      Memo1.Lines.Append('URI: '+JStringToString(imageUri.toString));

      LocalFilePath := CopyUriToPrivateFile(imageUri);
      if LocalFilePath <> '' then
      begin
        Memo1.Lines.Append('本地文件路径:' + LocalFilePath);
        if FileExists(LocalFilePath) then
        begin
          Image1.Bitmap.LoadFromFile(LocalFilePath);
          Memo1.Lines.Append('图片加载成功');
          Result := True;
        end
        else
          Memo1.Lines.Append('本地文件不存在');
      end;
    end;
    Invalidate;
  end;
end;

关键说明:

  • SharedActivity.getFilesDir:获取应用的私有内部存储目录,只有当前应用能访问,无需额外权限
  • 复制流的过程是标准的文件读写操作,完成后就能用普通的文件路径访问了

注意事项

  • Android 10及以上采用Scoped Storage机制,禁止直接访问其他应用的私有文件,必须通过Content Provider的URI+ContentResolver来访问,这也是为什么你直接用URI当路径不行的核心原因
  • 确保你的应用声明了必要的权限:如果是访问外部存储的图片,需要在AndroidManifest.xml中添加<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />(Android 13及以上可以用READ_MEDIA_IMAGES)

内容的提问来源于stack exchange,提问作者Holger Hanschmann

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 15:13:18