【问题标题】:Get Path from another app (WhatsApp)从另一个应用程序(WhatsApp)获取路径
【发布时间】:2017-06-09 19:42:36
【问题描述】:

我没有从我从 whatsApp 收到的 uri 中获取图像或视频的路径。

Uri 是这样的:content://com.whatsapp.provider.media/item/16695

来自 Gallery、Downloads 和其他媒体的媒体都很好。

有人知道如何获取路径吗?这是我正在使用的代码:

public String getMediaPath(Context context, Uri uri) {

    if (DEBUG)
        Log.d(TAG + " File -",
                "Authority: " + uri.getAuthority() +
                        ", Fragment: " + uri.getFragment() +
                        ", Port: " + uri.getPort() +
                        ", Query: " + uri.getQuery() +
                        ", Scheme: " + uri.getScheme() +
                        ", Host: " + uri.getHost() +
                        ", Segments: " + uri.getPathSegments().toString()
        );

    // DocumentProvider
    if (DocumentsContract.isDocumentUri(context, uri)) {
        // ExternalStorageProvider
        if (isExternalStorageDocument(uri)) {
            final String docId = DocumentsContract.getDocumentId(uri);
            final String[] split = docId.split(":");
            final String type = split[0];

            if ("primary".equalsIgnoreCase(type)) {
                return Environment.getExternalStorageDirectory() + "/" + split[1];
            }


        }
        // DownloadsProvider
        else if (isDownloadsDocument(uri)) {

            final String id = DocumentsContract.getDocumentId(uri);
            final Uri contentUri = ContentUris.withAppendedId(
                    Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));

            return getDataColumn(context, contentUri, null, null);
        }
        // MediaProvider
        else if (isMediaDocument(uri)) {
            final String docId = DocumentsContract.getDocumentId(uri);
            final String[] split = docId.split(":");
            final String type = split[0];

            Uri contentUri = null;
            if ("image".equals(type)) {
                contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
            } else if ("video".equals(type)) {
                contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
            } else if ("audio".equals(type)) {
                contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
            }

            final String selection = "_id=?";
            final String[] selectionArgs = new String[] {
                    split[1]
            };

            return getDataColumn(context, contentUri, selection, selectionArgs);
        }
    }
    // MediaStore (and general)
    else if ("content".equalsIgnoreCase(uri.getScheme())) {

        // Return the remote address
        if (isGooglePhotosUri(uri)) {
            return uri.getLastPathSegment();
        }

        return getDataColumn(context, uri, null, null);
    }
    // File
    else if ("file".equalsIgnoreCase(uri.getScheme())) {
        return uri.getPath();
    }

    return null;

}

public String getDataColumn(Context context, Uri uri, String selection,
                            String[] selectionArgs) {

    Cursor cursor = null;
    final String[] column = { MediaStore.Images.Media.DATA };
    final String[] projection = {
            column[0]
    };

    try {
        cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
                null);
        if (cursor != null && cursor.moveToFirst()) {
            if (DEBUG)
                DatabaseUtils.dumpCursor(cursor);

            final int index = cursor.getColumnIndexOrThrow(column[0]);
            return cursor.getString(index);
        }
    } finally {
        if (cursor != null)
            cursor.close();
    }
    return null;
}

public static boolean isExternalStorageDocument(Uri uri) {
    return "com.android.externalstorage.documents".equals(uri.getAuthority());
}

public static boolean isDownloadsDocument(Uri uri) {
    return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}

public static boolean isMediaDocument(Uri uri) {
    return "com.android.providers.media.documents".equals(uri.getAuthority());
}

public static boolean isGooglePhotosUri(Uri uri) {
    return "com.google.android.apps.photos.contentprovider".equals(uri.getAuthority());
}

这个日志的结果:

    if (DEBUG)
    Log.d(TAG + " File -",
            "Authority: " + uri.getAuthority() +
                    ", Fragment: " + uri.getFragment() +
                    ", Port: " + uri.getPort() +
                    ", Query: " + uri.getQuery() +
                    ", Scheme: " + uri.getScheme() +
                    ", Host: " + uri.getHost() +
                    ", Segments: " + uri.getPathSegments().toString()
    );

这是:

Authority: com.whatsapp.provider.media, Fragment: null, Port: -1, Query: null, Scheme: content, Host: com.whatsapp.provider.media, Segments: [item, 16348]

getDataColumn 上的光标如下所示:

>>>>> Dumping cursor 
android.content.ContentResolver$CursorWrapperInner@1fc81ac
I/System.out: 0 {
I/System.out: }
I/System.out: <<<<<

【问题讨论】:

    标签: android path uri whatsapp


    【解决方案1】:

    你可以试试这个对你有帮助。你不能直接从 WhatsApp 获取路径。如果你需要一个文件路径,首先复制文件并发送新的文件路径。 使用下面的代码

     public static String getFilePathFromURI(Context context, Uri contentUri) {
        String fileName = getFileName(contentUri);
        if (!TextUtils.isEmpty(fileName)) {
            File copyFile = new File(TEMP_DIR_PATH  + fileName+".jpg");
            copy(context, contentUri, copyFile);
            return copyFile.getAbsolutePath();
        }
        return null;
    }
    
    public static String getFileName(Uri uri) {
        if (uri == null) return null;
        String fileName = null;
        String path = uri.getPath();
        int cut = path.lastIndexOf('/');
        if (cut != -1) {
            fileName = path.substring(cut + 1);
        }
        return fileName;
    }
    
    public static void copy(Context context, Uri srcUri, File dstFile) {
        try {
            InputStream inputStream = context.getContentResolver().openInputStream(srcUri);
            if (inputStream == null) return;
            OutputStream outputStream = new FileOutputStream(dstFile);
            IOUtils.copy(inputStream, outputStream);
            inputStream.close();
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    

    那么 IOUtils 类如下所示

    public class IOUtils {
    
    
    
    private static final int BUFFER_SIZE = 1024 * 2;
    
    private IOUtils() {
        // Utility class.
    }
    
    public static int copy(InputStream input, OutputStream output) throws Exception, IOException {
        byte[] buffer = new byte[BUFFER_SIZE];
    
        BufferedInputStream in = new BufferedInputStream(input, BUFFER_SIZE);
        BufferedOutputStream out = new BufferedOutputStream(output, BUFFER_SIZE);
        int count = 0, n = 0;
        try {
            while ((n = in.read(buffer, 0, BUFFER_SIZE)) != -1) {
                out.write(buffer, 0, n);
                count += n;
            }
            out.flush();
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                Log.e(e.getMessage(), e.toString());
            }
            try {
                in.close();
            } catch (IOException e) {
                Log.e(e.getMessage(), e.toString());
            }
        }
        return count;
    }
    
    
    }
    

    【讨论】:

      【解决方案2】:

      你可以试试这个,然后你会得到一个选定图像的位图,然后你可以很容易地从设备默认图库中找到它的本机路径。

      Bitmap roughBitmap= null;
          try {
          // Works with content://, file://, or android.resource:// URIs
          InputStream inputStream =
          getContentResolver().openInputStream(uri);
          roughBitmap= BitmapFactory.decodeStream(inputStream);
      
          // calc exact destination size
          Matrix m = new Matrix();
          RectF inRect = new RectF(0, 0, roughBitmap.Width, roughBitmap.Height);
          RectF outRect = new RectF(0, 0, dstWidth, dstHeight);
          m.SetRectToRect(inRect, outRect, Matrix.ScaleToFit.Center);
          float[] values = new float[9];
          m.GetValues(values);
      
      
          // resize bitmap if needed
          Bitmap resizedBitmap = Bitmap.CreateScaledBitmap(roughBitmap, (int) (roughBitmap.Width * values[0]), (int) (roughBitmap.Height * values[4]), true);
      
          string name = "IMG_" + new Java.Text.SimpleDateFormat("yyyyMMdd_HHmmss").Format(new Java.Util.Date()) + ".png";
          var sdCardPath= Environment.GetExternalStoragePublicDirectory("DCIM").AbsolutePath;
          Java.IO.File file = new Java.IO.File(sdCardPath);
          if (!file.Exists())
          {
              file.Mkdir();
          }
          var filePath = System.IO.Path.Combine(sdCardPath, name);
          } catch (FileNotFoundException e) {
          // Inform the user that things have gone horribly wrong
          }
      

      【讨论】:

      • 我得到了位图,但是我怎样才能得到它的路径
      • @Eduardo Bonfa ,获取位图后,您可以将其转换为文件并获取此文件的路径。我已编辑答案
      • 这适用于图像,是否也适用于其他媒体?
      • 这不起作用。 getContentResolver().openInputStream(uri); 抛出异常。请检查this问题。
      • @Atul ,抛出哪种异常?
      【解决方案3】:

      您无法从 WhatsApp 获取文件路径。他们现在不暴露它。你唯一能得到的是InputStream:

      InputStream is = getContentResolver().openInputStream(Uri.parse("content://com.whatsapp.provider.media/item/16695"));
      

      使用is,您可以在您的应用中显示来自 WhatsApp 的图片。

      【讨论】:

      • 这不起作用。 OpenInputStream 抛出异常。请检查this问题。
      • 我已经在我的 LG Stylus 3 (Android 7.0) 上检查了这个,它解决了这个问题。你在你的手机上试过了吗?
      • 在棉花糖上是的。请注意,自从 WhatsApp 推出其最新更新版本后,就会发生此异常。以前它工作正常(我认为他们只是共享图像文件路径file://)但现在他们使用content://共享
      • 我不确定 WhatsApp 的最新版本,但我检查了 Uri 有一个方案 content - 它是一个 "content://com.whatsapp.provider.media/item/xxxxx"。我会在棉花糖上检查它。
      • 好的,我发现了问题。我们需要从初始活动本身调用openInputStream,该活动在我们从 WhatsApp 共享图像后启动。我将 URI 存储在初始活动中,并从另一个活动中调用 openInputStream。这会引发异常。
      【解决方案4】:

      如果要将照片上传到服务器,还可以将 URI 转换为文件,然后再转换为字节。

      查看:https://www.stackoverflow.com/a/49575321

      【讨论】:

        【解决方案5】:

        使用下面的代码示例将返回位图:

        BitmapFactory.decodeStream(getContentResolver().openInputStream(Uri.parse("content://com.whatsapp.provider.media/item/128752")))
        

        之后你们都知道自己该做什么了。

        【讨论】:

        • 问题是从Uri获取文件路径,而不是将文件路径转换为uri
        【解决方案6】:

        它适用于我打开小文本文件...我没有尝试在其他文件中

        protected void viewhelper(Intent intent) {
            Uri a = intent.getData();
            if (!a.toString().startsWith("content:")) {
                return;
            }
            //Ok Let's do it
            String content = readUri(a);
            //do something with this content
        }
        

        这里是 readUri(Uri uri) 方法

        private String readUri(Uri uri) {
            InputStream inputStream = null;
            try {
                inputStream = getContentResolver().openInputStream(uri);
                if (inputStream != null) {
                    byte[] buffer = new byte[1024];
                    int result;
                    String content = "";
                    while ((result = inputStream.read(buffer)) != -1) {
                        content = content.concat(new String(buffer, 0, result));
                    }
                    return content;
                }
            } catch (IOException e) {
                Log.e("receiver", "IOException when reading uri", e);
            } finally {
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        Log.e("receiver", "IOException when closing stream", e);
                    }
                }
            }
            return null;
        }
        

        我从这个存储库获得它https://github.com/zhutq/android-file-provider-demo/blob/master/FileReceiver/app/src/main/java/com/demo/filereceiver/MainActivity.java
        我修改了一些代码以使其正常工作。

        清单文件:

            <activity android:name=".MainActivity">
                <intent-filter >
                    <action android:name="android.intent.action.VIEW" />
                    <category android:name="android.intent.category.DEFAULT" />
                    <data android:mimeType="*/*" />
                </intent-filter>
            </activity>
        

        你需要添加

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            /*
             *    Your OnCreate
             */
            Intent intent = getIntent();
            String action = intent.getAction();
            String type = intent.getType();
        
            //VIEW"
            if (Intent.ACTION_VIEW.equals(action) && type != null) {
                viewhelper(intent); // Handle text being sent
            }
          }
        

        【讨论】:

          【解决方案7】:

          protected void onCreate(Bundle savedInstanceState) { /* * 你的 OnCreate */ 意图意图 = getIntent(); 字符串动作 = intent.getAction(); 字符串类型 = intent.getType();

          //VIEW"
          if (Intent.ACTION_VIEW.equals(action) && type != null) {viewhekper(intent);//Handle text being sent}
          

          【讨论】:

          • 你能描述一下为什么这个代码是解决方案而不是仅仅发布代码吗?
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-12-02
          • 2017-06-27
          • 2023-03-31
          • 2011-04-24
          • 1970-01-01
          相关资源
          最近更新 更多