【问题标题】:How to create a file that other applications (Polaris Office) can read only?如何创建其他应用程序(Polaris Office)只能读取的文件?
【发布时间】:2013-04-05 02:31:50
【问题描述】:

这是我想要在我的应用程序中执行的操作。我下载文件(docx、pptx、pdf、mov 等)并将它们存储在File 中。下载文件后,我希望用户能够打开并阅读它。 我不希望用户能够修改File

这是我尝试实现的方法。

            String uri =   nameFileStatic + extension;
            RestClientGetAsFile client = new RestClientGetAsFile(url, getActivity(), uri) {
                @Override
                protected void onPostExecute(File results) {
                    if (results != null) {
                        if (results.exists()) {
                            Uri path = Uri.fromFile(results);
                            Intent intent = new Intent(Intent.ACTION_VIEW);
                            intent.setDataAndType(path, type); //type
                            intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                            try {
                                startActivity(intent);
                            } catch (ActivityNotFoundException e) {
                                Toast.makeText(DescriberAttachments.this.getActivity(),
                                        "No Application Available to View file with extension " + extension, Toast.LENGTH_SHORT).show();
                            }
                        }
                    }
                }
            };
            client.execute();

基本上,我在 AsyncTask 实例中下载文件。然后在 onPostExecute() 方法中,我使用 Intent 打开文件。

现在的问题是:在哪里存储文件?这是我尝试过的:

  • uri = getDir("SLIMS", Context.MODE_WORLD_READABLE ).getAbsolutePath() + "/Attachments/myfile.docx"。在保存文件之前,我总是确保目录存在。
File directoryMain = new File(getDir("SLIMS", Context.MODE_PRIVATE).getAbsolutePath());
directoryMain.mkdir();
File directoryAttachments = new File( getDir("SLIMS",  Context.MODE_PRIVATE).getAbsolutePath() + "/Attachments");
directoryAttachments.mkdir();

很遗憾,之后我无法打开文件...我收到一条消息错误(来自 Polaris Office),但在我的日志中找不到任何相关消息。

  • uri = getFilesDir() + "/Attachments/myfile.docx". 我得到了与上一点相同的错误。

  • uri = Environment.getExternalStorageDirectory() + "/Attachments/myfile.docx"。这次我可以在 Polaris Office 中打开文件,但我无法将 File 设为只读。我尝试了myFile.setReadOnly()myFile.setReadable(true)myFile.setWritable(false),但最后我仍然能够修改文件。

所以我想现在我仍会将这些文件存储在 sdcard 中,但我真的对写权限感到恼火。

有什么建议吗?

【问题讨论】:

    标签: android android-intent android-sdcard android-file android-permissions


    【解决方案1】:

    在您的应用内创建一个ContentProvider 并启动查看器应用并引用内容方案,例如content://com.mydomain.myapp/file/filename.jpg

    【讨论】:

    • 感谢您的回答。我会试试这个,稍后再提供一些反馈。
    • 到目前为止,我从未使用过 Content Provider,而且它似乎很复杂。你能给我一些关键点来实现我正在尝试做的事情吗?例如,我应该使用哪些类以及应该覆盖哪些方法?
    【解决方案2】:

    正如323go 建议的那样,我实现了一个ContentProvider。我的代码来自CommonsWare's post

    这是我下载文件的代码。下载文件后,我将其保存为“ComingFromSLIMSDatabase”+ 扩展名。扩展名可以是 docx、pptx、pdf 等。下载文件后,我调用 start 一个带有隐式 Intent 的 Activity 并提供内容提供者的 uri。

    String uri = nameFileStatic + extension;
                RestClientGetAsFile client = new RestClientGetAsFile(url, getActivity(), uri) {
                    @Override
                    protected void onPostExecute(File results) {
                        if (results != null) {
                            if (results.exists()) {
                                results.setReadable(true);
                                try {
                                    startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(AttachmentProvider.CONTENT_URI
                                            + "ComingFromSLIMSDatabase" + extension)));
                                } catch (ActivityNotFoundException e) {
                                    Toast.makeText(DescriberAttachments.this.getActivity(),
                                            "No Application Available to View file with extension " + extension, Toast.LENGTH_SHORT).show();
                                }
                            }
                        }
                    }
                };
                client.execute();
    

    然后 ContentProvider 捕获调用并打开我要显示的文件。

    public class FileProvider extends ContentProvider {
      public static final Uri CONTENT_URI=Uri.parse("content://com.commonsware.android.cp.files/");
      private static final HashMap<String, String> MIME_TYPES=new HashMap<String, String>();
    
      static {
        MIME_TYPES.put(".pdf", "application/pdf");
      }
    
      @Override
      public boolean onCreate() {
        File f=new File(getContext().getFilesDir(), "test.pdf");
    
        if (!f.exists()) {
          AssetManager assets=getContext().getResources().getAssets();
    
          try {
            copy(assets.open("test.pdf"), f);
          }
          catch (IOException e) {
            Log.e("FileProvider", "Exception copying from assets", e);
    
            return(false);
          }
        }
    
        return(true);
      }
    
      @Override
      public String getType(Uri uri) {
        String path=uri.toString();
    
        for (String extension : MIME_TYPES.keySet()) {
          if (path.endsWith(extension)) {
            return(MIME_TYPES.get(extension));
          }
        }
    
        return(null);
      }
    
      @Override
      public ParcelFileDescriptor openFile(Uri uri, String mode)
        throws FileNotFoundException {
        String path = uri.getPath();
        File f=new File(getContext().getFilesDir(),path);
        if (f.exists()) {
          return(ParcelFileDescriptor.open(f,
                                            ParcelFileDescriptor.MODE_READ_ONLY));
        }
    
        throw new FileNotFoundException(uri.getPath());  
      }
    
      @Override
      public Cursor query(Uri url, String[] projection, String selection,
                            String[] selectionArgs, String sort) {
        throw new RuntimeException("Operation not supported");
      }
    
      @Override
      public Uri insert(Uri uri, ContentValues initialValues) {
        throw new RuntimeException("Operation not supported");
      }
    
      @Override
      public int update(Uri uri, ContentValues values, String where, String[] whereArgs) {
        throw new RuntimeException("Operation not supported");
      }
    
      @Override
      public int delete(Uri uri, String where, String[] whereArgs) {
        throw new RuntimeException("Operation not supported");
      }
    
      static private void copy(InputStream in, File dst) throws IOException {
        FileOutputStream out=new FileOutputStream(dst);
        byte[] buf=new byte[1024];
        int len;
    
        while((len=in.read(buf))>0) {
          out.write(buf, 0, len);
        }
    
        in.close();
        out.close();
      }
    }
    

    使用此方法,即使文件存储在 Context.getFilesDir() 中,用户也可以打开文件。现在我仍然很困惑。因为如果我打开一个 doc 文件,我仍然可以修改它并将其保存在其他地方。目前这不是一个理想的功能。

    我想知道是否有人知道一种无需让其他应用程序将其保存在其他位置即可查看文件内容的方法

    【讨论】:

    • 如果不受您控制的其他应用程序可以访问您的数据,您无法阻止它保存该数据。您可以防止它覆盖您的文件或数据库中的数据。
    • 好的。我也是这么想的。谢谢你的回答!
    猜你喜欢
    • 2018-02-12
    • 1970-01-01
    • 1970-01-01
    • 2011-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-25
    相关资源
    最近更新 更多