2013-09-25 2 views
3

이 질문에는 몇 가지 하위 질문이 포함되어 있습니다. 나는 this question에 의해 시작, 이들을 포크입니다. 결국이 질문을 삭제하여 정리할 것입니다.FileProvider의 Hello World

다음 프로그램은 이론상 세계의 텍스트 파일을 공유합니다. 코드가 실행되지만 Dropbox 또는 Gmail에 공유하는 것은 실패합니다 (두 가지 구체적인 예를 통해). 이외에도 고해상도/값/strings.xml의에서 send_to 값을 추가하는

public class MainActivity extends Activity { 
    @Override protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     String filename = "hellow.txt"; 
     String fileContents = "Hello, World!\n"; 
     byte[] bytes = fileContents.getBytes(); 
     FileOutputStream fos = null; 
     try { 
      fos = this.openFileOutput(filename, MODE_PRIVATE); 
      fos.write(bytes); 
     } catch (IOException e) {      
      e.printStackTrace(); 
     } finally { 
      try { 
       fos.close(); 
      } catch (IOException e) {      
       e.printStackTrace(); 
      } 
     } 

     File file = new File(filename); 
     Intent shareIntent = new Intent(); 
     shareIntent.setAction(Intent.ACTION_SEND); 
     shareIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file)); 
     shareIntent.setType("application/txt"); 
     startActivity(Intent.createChooser(shareIntent, getResources().getText(R.string.send_to))); 

     file.delete(); 
    } 
} 

, 이클립스가 생성하는 일반 Hello, World에게 한 변화의 유일한 쌍의 AndroidManifest.xml에 다음 <provider> 태그를 추가한다 :

<application 
    android:allowBackup="true" 
    android:icon="@drawable/ic_launcher" 
    android:label="@string/app_name" 
    android:theme="@style/AppTheme" > 

    <provider 
     android:name="android.support.v4.content.FileProvider" 
     android:authorities="com.mycorp.helloworldtxtfileprovider.MainActivity" 
     android:exported="false" 
     android:grantUriPermissions="true" > 
     <meta-data 
      android:name="android.support.FILE_PROVIDER_PATHS" 
      android:resource="@xml/my_paths" /> 
    </provider> 

    <activity 
     android:name="com.mycorp.helloworldtxtfileprovider.MainActivity" 
     ... 

... 그리고 입술에 다음을 추가/XML/my_paths.xml

<paths xmlns:android="http://schemas.android.com/apk/res/android"> 
    <files-path name="files" path="." /> 
</paths> 

내 주요 질문은 전나무이다 st,하지만이 주제를 다룰 때 2-4의 질문에 대한 토론도 흥미로울 것입니다.

  1. 왜 위의 프로그램이 실패합니까?
  2. 사용자 정의 ContentProvider이 필요한 경우 해당 클래스를 확장해야하지만 실제로는 FileProvider이 필요한 경우 파생없이 해당 클래스를 사용할 수 있습니까?
  3. 이 코드에서는 openFileOutput으로 filename을 두 번 한 번 사용하고 new File()을 사용해야했습니다. 이 중복을 피할 수있는 방법이 있습니까 (동일한 파일이 참조되는 것을 보장 할 수 있습니까?)
  4. startActivity(..)이 호출 된 직후에 파일을 삭제하는 것이 안전합니까? 아니면 파일이 업로드/공유되었음을 알기 위해 콜백을 고안해야합니다. (실제 파일은/업로드를 공유 할 수있는 시간이 걸릴 수 있습니다.)

편집

코드는 잘 실행하고 보낼 수있는 응용 프로그램의 목록을 보여줍니다.

Dropbox를 선택하면 위치를 올바르게 선택할 수 있습니다. Dropbox는 "Dropbox에 업로드"와 "Upload failed : my_file.txt"라는 알림을 보냅니다.

Gmail을 선택하면받는 사람을 채울 수 있으며 파일이 첨부 된 것처럼 보이지만 "메시지 보내기"후에 "첨부 파일을 보낼 수 없습니다"라는 메시지가 나타납니다.

+3

다른 사람들이 대답 할 시간이없는 질문은 삭제하고 삭제하지 않는 것이 좋습니다. 질문은 귀하의 이익을위한 것이 아니라 미래에 많은 사람들이 비슷한 것을 찾고있는 사람들을위한 것입니다. –

+0

@BradLarson 한 질문/한 게시물 규칙을 위반하고 가격을 지불하고 있습니다. 그렇게함으로써 질문의 요점을 해결하지 않고 덜 중요한 문제에 합리적인 대답을함으로써 도움을 얻으려는 사람과 같은 친절한 영혼을 열어 놓았습니다 (1 부). 의견에서 언급했듯이 질문을 하위 파트로 나누고 있습니다. 나는 파트 1에 초점을 맞춘 질문을 시도했다. 아무도 대답을 모색하지 않았다. 나는 그것을 삭제하는 것을 선호했다. 궁극적으로 질문을 한 후 사용자가 비행 모드에있을 때 문제가 훨씬 더 복잡하다는 것을 깨달았습니다. TBC. – Calaf

답변

0

2. 예, 실제로입니다. ContentProvider은 추상 클래스이므로 사용자 정의 컨텐츠 공급자를 사용하려면 반드시 확장해야합니다. FileProviderContentProvider (추상이 아님)의 하위 클래스이므로 프로그래머는 하위 클래스를 지정하지 않고 FileProvider을 사용할 수 있습니다. 당신이 startActivity()를 호출 후 바로 파일을 삭제하는 것이 안전 아니라,

String fileName = "my_file.txt"; 
String fileData = "sample file content"; 

// Get the file 
File file = new File(this.getFilesDir(), fileName); 
if (!file.exists()) { 
    file.createNewFile(); 
} 

// Write data to file 
FileWriter fileWriter = new FileWriter(file); 
fileWriter.write(fileData); 
fileWriter.close(); 

// Get the uri 
Uri uri = Uri.fromFile(file); 

// Share the file with corresponding uri 
Intent shareIntent = new Intent(); 
shareIntent.setAction(Intent.ACTION_SEND); 
shareIntent.putExtra(Intent.EXTRA_STREAM, uri); 
shareIntent.setType("application/txt"); 
startActivity(Intent.createChooser(shareIntent, "Send To")); 

4.No -

3.For 보장 같은 파일 아래의 샘플 코드를 따를 수 있습니다. startActivity()은 non-blocking 함수 호출이므로 즉시 반환됩니다. 파일이 공유되는 시간을 기다려야합니다.startActivityForResult()을 사용하면됩니다. 목적에 부합하는지 확인하십시오.

+0

나는이 양식에서 파트 2에 어떻게 물어볼 수 있었는지 놀랍다. 어쨌든 내 코드를 당신 코드로 대체하는 것이 도움이되지 않습니다. 당신이 당신의 편에서 그것을 실행하고 그것이 작동하는지 확인해 주시겠습니까? 당신은 try-catch 블록을 놓 쳤기 때문에 당신이 그것을 실행하지 않았다고 추측합니다. – Calaf

+0

이 코드는 동일한 파일 객체를 사용할 수 있다는 아이디어를 얻기위한 것입니다. 당신이 가까와서 코드를 성공적으로 컴파일했습니다. 코드를 실행하고 파일을 공유하도록 선택할 수있는 앱 목록을 표시합니다. 게시하는 동안 try-catch 블록을 제거했습니다. – imranhasanhira

+0

내가 게시 한 코드도 제대로 실행되고 보낼 앱 목록을 제공합니다. Dropbox 및 Gmail에서받은 알림으로 질문을 업데이트했습니다. 당신이 당신 편에 업로드 할 수 있다는 것을 확인할 수 있습니까? – Calaf

6

1.

사용 FileProvider.getUriForFile(...)은 URI를 구성합니다. 이렇게하면 시작된 활동이 FileProvider로 전달되고 (그러면 해당 파일을 앱의 개인 파일 디렉토리에서 제공 할 수 있습니다). Uri.fromFile(...)은 시작된 활동이 개인 디렉터리에 직접 액세스하려고하기 때문에 작동하지 않습니다.

설정 FLAG_GRANT_READ_URI_PERMISSION 그래서 시작 활동이 부여하는 FileProvider에 의해 구축 된 URI에 대한 읽기 권한을.

마지막으로, "텍스트/일반"MIME 유형으로 "응용 프로그램/TXT"보다 더 나은 작동 할 수 있습니다.

장치간에 일관되게 작동하도록하는 데 몇 가지 문제가있었습니다. 이것은 (내가 그것을 수정하는 경우 수정합니다) 지금까지 내 가장 좋은 방법입니다 :

final String auth = "org.volley.sndcard_android.fileprovider"; 
    final Uri uri = FileProvider.getUriForFile(activity, auth, file); 
    final String type = activity.getContentResolver().getType(uriForFile); 

    final Intent shareIntent = new Intent(Intent.ACTION_SEND); 
    shareIntent.setDataAndType(uri, type); 
    shareIntent.putExtra(Intent.EXTRA_STREAM, uriForFile); 
    shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 
    final Intent chooser = Intent.createChooser(shareIntent, "<title>"); 
    activity.startActivity(chooser); 

은 유형 내 넥서스 5에서 작동하지만 내 삼성 태블릿에 설정. 삼성 태블릿이 허가를 얻기 위해 URI를 데이터로 필요로하는 것 같습니다. 또한 intent.getData()은 앞의 모든 호출을 intent.setType()으로 취소하며 그 반대의 경우도 있으므로 위와 같이 결합 된 방법을 사용해야합니다.

Gmail이 추가 데이터를 기본 수신인 주소로 해석하는 것으로 보입니다. 매우 짜증나! 누구든지 더 나은 해결책을 가지고 있다면 그것을 공유하십시오 (의도적 인 말장난, 나는 Gothenburg 출신입니다).

+1

FileProvider를 사용하여 내 앱의 보안 저장소에서 파일을 첨부 할 수 있었던 유일한 방법은 수동으로 파일에 대한 권한을 부여하고 취소하는 것입니다.이 대답의 http://stackoverflow.com/a/18332000/1082344 (Samsung Galaxy Tab 10.1 안드로이드 버전 3.1, 안드로이드 2.3.4가있는 갤럭시 에이스, 안드로이드 4.1.2가있는 갤럭시 S3) – IsaacCisneros