2012-08-29 15 views
40

मेरा लक्ष्य आंतरिक संग्रहण पर एक XML फ़ाइल बनाना है और फिर इसे शेयर इरादे से भेजना है।आंतरिक संग्रहण से फ़ाइल बनाएं और साझा करें

मैं इस कोड

FileOutputStream outputStream = context.openFileOutput(fileName, Context.MODE_WORLD_READABLE); 
PrintStream printStream = new PrintStream(outputStream); 
String xml = this.writeXml(); // get XML here 
printStream.println(xml); 
printStream.close(); 

मैं इसे साझा करने के लिए आउटपुट फ़ाइल के लिए एक उरी प्राप्त करने का प्रयास कर रहा हूँ अटक का उपयोग कर एक एक्सएमएल फ़ाइल बनाने में सक्षम हूँ। मैं पहली बार एक उरी के लिए फ़ाइल को परिवर्तित करके फ़ाइल का उपयोग करने की कोशिश की

File outFile = context.getFileStreamPath(fileName); 
return Uri.fromFile(outFile); 

यह फ़ाइल रिटर्न: ///data/data/com.my.package/files/myfile.xml लेकिन मैं करने के लिए प्रकट नहीं कर सकता इसे ईमेल, अपलोड, इत्यादि से संलग्न करें

यदि मैं मैन्युअल रूप से फ़ाइल की लंबाई की जांच करता हूं, तो यह उचित है और दिखाता है कि एक उचित फ़ाइल आकार है।

अगला मैंने एक सामग्री प्रदाता बनाया और फ़ाइल को संदर्भित करने का प्रयास किया और यह फ़ाइल के लिए मान्य संभाल नहीं है। ContentProvider को कभी भी कोई बिंदु नहीं कहा जाता है।

Uri uri = Uri.parse("content://" + CachedFileProvider.AUTHORITY + "/" + fileName); 
return uri; 

यह सामग्री प्रस्तुत करती है: //com.my.package.provider/myfile.xml लेकिन मैं फ़ाइल की जांच कर यह शून्य लंबाई है।

मैं फ़ाइलों को सही तरीके से कैसे एक्सेस करूं? क्या मुझे सामग्री प्रदाता के साथ फाइल बनाने की ज़रूरत है? यदि हां, तो कैसे?

अद्यतन

यहाँ कोड मैं साझा करने के लिए उपयोग कर रहा हूँ है। अगर मैं जीमेल का चयन करता हूं, तो यह एक अटैचमेंट के रूप में दिखाता है लेकिन जब मैं इसे भेजता हूं तो त्रुटि संलग्नक नहीं दिखा सका और आने वाले ईमेल में कोई अनुलग्नक नहीं है।

public void onClick(View view) { 
    Log.d(TAG, "onClick " + view.getId()); 

    switch (view.getId()) { 
     case R.id.share_cancel: 
      setResult(RESULT_CANCELED, getIntent()); 
      finish(); 
      break; 

     case R.id.share_share: 

      MyXml xml = new MyXml(); 
      Uri uri; 
      try { 
       uri = xml.writeXmlToFile(getApplicationContext(), "myfile.xml"); 
       //uri is "file:///data/data/com.my.package/files/myfile.xml" 
       Log.d(TAG, "Share URI: " + uri.toString() + " path: " + uri.getPath()); 

       File f = new File(uri.getPath()); 
       Log.d(TAG, "File length: " + f.length()); 
       // shows a valid file size 

       Intent shareIntent = new Intent(); 
       shareIntent.setAction(Intent.ACTION_SEND); 
       shareIntent.putExtra(Intent.EXTRA_STREAM, uri); 
       shareIntent.setType("text/plain"); 
       startActivity(Intent.createChooser(shareIntent, "Share")); 
      } catch (FileNotFoundException e) { 
       e.printStackTrace(); 
      } 

      break; 
    } 
} 

मैंने देखा है कि वहाँ एक ExceptioncreateChooser (...) अंदर से यहां फेंक दिया है, लेकिन मैं समझ नहीं क्यों यह फेंक दिया है।

ई/ActivityThread (572): गतिविधि com.android.internal.app.ChooserActivity IntentReceiver [email protected] कि मूल रूप से यहाँ पंजीकृत था लीक किया गया है। क्या आप unregisterReceiver() पर कॉल खो रहे हैं?

मैंने इस त्रुटि का शोध किया है और कुछ भी स्पष्ट नहीं मिला है। इन दोनों लिंक से पता चलता है कि मुझे एक रिसीवर को अपंजीकृत करने की आवश्यकता है।

मैं एक रिसीवर सेटअप है, लेकिन यह एक AlarmManager कि कहीं सेट किया गया है और/अपंजीकृत रजिस्टर करने के लिए एप्लिकेशन की आवश्यकता नहीं है के लिए है।

openFile के लिए कोड (...)

यदि आवश्यक हो, तो यहां सामग्री प्रदाता मैंने बनाया है।

public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { 
    String fileLocation = getContext().getCacheDir() + "/" + uri.getLastPathSegment(); 

    ParcelFileDescriptor pfd = ParcelFileDescriptor.open(new File(fileLocation), ParcelFileDescriptor.MODE_READ_ONLY); 
    return pfd; 
} 
+0

मुझे लगता है कि सामग्री बनाने के बजाय पहली विधि को काम करना चाहिए प्रदाता। ContentProvider का उपयोग पूरी फ़ाइल के बजाय डेटा वापस करने के लिए किया जाता है, यह आपकी आवश्यकताओं को पूरा नहीं करेगा। मेरा अनुमान है कि आपके एक्सएमएल को संभालने के लिए कोई ऐप नहीं है। क्या आप उस कोड को पोस्ट कर सकते हैं जहां आपका शेयर इरादा बनाया जा रहा है – nandeesh

+0

यदि कोड इसे अधिक स्पष्ट बनाता है और साथ ही एक अपवाद भी है, तो मुझे यह समझ में नहीं आता कि यह संबंधित है या नहीं। – Kirk

+0

क्या आपने एक सामग्री प्रदाता बनाया है? यदि आपके पास है, तो क्या आप इसके लिए अपना कोड पोस्ट कर सकते हैं। यदि आपको ContentProvider बनाने और OpenFile विधि को ओवरराइड करने की आवश्यकता नहीं है। उस विधि को जीमेल द्वारा बुलाया जाएगा जब यह सामग्री से जुड़े फाइल को खोलने का प्रयास करता है: //com.my.package.provider/myfile.xml uri। – Rob

उत्तर

35

सामग्री ऐप्स के माध्यम से अपने ऐप्स निजी निर्देशिका में संग्रहीत फ़ाइल का खुलासा करना संभव है। यहां कुछ उदाहरण कोड दिया गया है जो मैंने दिखाया है कि सामग्री प्रदाता कैसे बनाना है जो यह कर सकता है।

प्रकट

<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
    package="com.example.providertest" 
    android:versionCode="1" 
    android:versionName="1.0"> 

    <uses-sdk android:minSdkVersion="11" android:targetSdkVersion="15" /> 

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

    <activity 
     android:name=".MainActivity" 
     android:label="@string/app_name"> 
     <intent-filter> 
      <action android:name="android.intent.action.MAIN" /> 
      <category android:name="android.intent.category.LAUNCHER" /> 
     </intent-filter> 
    </activity> 

    <provider 
     android:name="MyProvider" 
     android:authorities="com.example.prov" 
     android:exported="true" 
     />   
    </application> 
</manifest> 

ParcelFileDescriptor वापस जाने के लिए

@Override 
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {  
    File cacheDir = getContext().getCacheDir(); 
    File privateFile = new File(cacheDir, "file.xml"); 

    return ParcelFileDescriptor.open(privateFile, ParcelFileDescriptor.MODE_READ_ONLY); 
} 

सुनिश्चित करें कि आप किसी अन्य कैश निर्देशिका

private void copyFileToInternal() { 
    try { 
     InputStream is = getAssets().open("file.xml"); 

     File cacheDir = getCacheDir(); 
     File outFile = new File(cacheDir, "file.xml"); 

     OutputStream os = new FileOutputStream(outFile.getAbsolutePath()); 

     byte[] buff = new byte[1024]; 
     int len; 
     while ((len = is.read(buff)) > 0) { 
      os.write(buff, 0, len); 
     } 
     os.flush(); 
     os.close(); 
     is.close(); 

    } catch (IOException e) { 
     e.printStackTrace(); // TODO: should close streams properly here 
    } 
} 

को अपने xml फ़ाइल की नकल की है अब करें कि आपके ContentProvider ओवरराइड OpenFile में ऐप आपके द्वारा निजी फाइल के लिए इनपुट इनपुट प्राप्त करने में सक्षम होना चाहिए जी सामग्री uri (सामग्री: //com.example.prov/myfile.xml)

एक साधारण परीक्षण के लिए, निम्न

private class MyTask extends AsyncTask<String, Integer, String> { 

    @Override 
    protected String doInBackground(String... params) { 

     Uri uri = Uri.parse("content://com.example.prov/myfile.xml"); 
     InputStream is = null;   
     StringBuilder result = new StringBuilder(); 
     try { 
      is = getApplicationContext().getContentResolver().openInputStream(uri); 
      BufferedReader r = new BufferedReader(new InputStreamReader(is)); 
      String line; 
      while ((line = r.readLine()) != null) { 
       result.append(line); 
      }    
     } catch (FileNotFoundException e) { 
      e.printStackTrace(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } finally { 
      try { if (is != null) is.close(); } catch (IOException e) { } 
     } 

     return result.toString(); 
    } 

    @Override 
    protected void onPostExecute(String result) { 
     Toast.makeText(CallerActivity.this, result, Toast.LENGTH_LONG).show(); 
     super.onPostExecute(result); 
    } 
} 
+1

उत्तर के लिए धन्यवाद। मैं निजी डेटा तक पहुंचने के लिए यदि संभव हो तो ContentProvider का उपयोग करने की उम्मीद कर रहा हूं। getExternalCacheDir() एपीआई 7 पर समर्थित नहीं है जिसे मुझे लक्षित करने की आवश्यकता है। – Kirk

+0

एपीआई 7 पर आप सार्वजनिक निर्देशिका प्राप्त करने के लिए getExternalStorageDirectory() का उपयोग कर सकते हैं। मुझे यकीन नहीं है कि एक सामग्री प्रदाता के साथ भी, फ़ाइल सिस्टम के निजी हिस्से को ऐप्स तक सार्वजनिक पहुंच प्रदान करना संभव है। – Rob

+0

सुझाव के लिए धन्यवाद। मैं एसडीकार्ड की बजाय आंतरिक भंडारण में लिखना चाहता हूं। इसे पूरा करने के तरीके पर कोई विचार? – Kirk

3

आप की जरूरत है के लिए इसी तरह एक अलग app से सामग्री प्रदाता फोन अनुमति अन्य एप्लिकेशन के लिए (शेयर के लिए, या अन्यथा) को अपने ऐप्लिकेशन के निजी फ़ाइलों को देखने के लिए आप कुछ समय बचाने के लिए और बस का उपयोग कर सकता है v4 compat लाइब्रेरी की FileProvider

13

तो रोब के जवाब सही मुझे लगता है, लेकिन मैं यह थोड़ा अलग किया । जहाँ तक मुझे प्रदाता में में सेटिंग के साथ समझने के रूप में,:

android:exported="true" 

आप अपनी सभी फ़ाइलों पर सार्वजनिक उपयोग दे रहे हैं ?! इस प्रकार आप file_paths.xml फ़ाइल को परिभाषित आपके XML निर्देशिका में

<provider 
    android:authorities="com.your.app.package" 
    android:name="android.support.v4.content.FileProvider" 
    android:exported="false" 
    android:grantUriPermissions="true"> 
    <meta-data 
     android:name="android.support.FILE_PROVIDER_PATHS" 
     android:resource="@xml/file_paths" /> 
</provider> 

और उसके बाद: वैसे भी, एक तरह से कुछ फ़ाइलों को केवल पहुँच प्रदान करने के निम्नलिखित तरीके से फ़ाइल पथ अनुमतियां निर्धारित करने के लिए है

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

अब, "allfiles" उसी प्रकार की सार्वजनिक अनुमति देता है जो मुझे लगता है कि विकल्प के रूप में मुझे लगता है: निर्यात किया गया = "सत्य" लेकिन आप वास्तव में नहीं चाहते हैं कि मुझे लगता है कि उपनिर्देशिका को परिभाषित करने के लिए अगली पंक्ति है। तो आपको बस उन फाइलों को स्टोर करना है जिन्हें आप साझा करना चाहते हैं, वहां उस डीआईआर में।

अगला जो आपको करना है, वह भी रॉब कहता है, इस फ़ाइल के लिए यूआरआई प्राप्त करें। , जब मैं इस URI है, मैं संलग्न करने के लिए यह अनुमति अन्य एप्लिकेशन इसका इस्तेमाल करने के लिए किया था

Uri contentUri = FileProvider.getUriForFile(context, "com.your.app.package", sharedFile); 

फिर: यह कैसे मैंने किया है। मैं कैमरे ऐप में इस फाइल यूआरआई का उपयोग या भेज रहा था। वैसे भी इस तरह से मैं कैसे अन्य एप्लिकेशन पैकेज की जानकारी और URI करने के लिए दी गई अनुमतियों को मिल गया है:

PackageManager packageManager = getPackageManager(); 
List<ResolveInfo> list = packageManager.queryIntentActivities(cameraIntent, PackageManager.MATCH_DEFAULT_ONLY); 
if (list.size() < 1) { 
    return; 
} 
String packageName = list.get(0).activityInfo.packageName; 
grantUriPermission(packageName, sharedFileUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION); 

ClipData clipData = ClipData.newRawUri("CAMFILE", sharedFileUri); 
cameraIntent.setClipData(clipData); 
cameraIntent.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 
cameraIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 
startActivityForResult(cameraIntent, GET_FROM_CAMERA); 

मैं कैमरे के लिए कोड को छोड़ दिया के रूप में मैं कुछ अन्य उदाहरण मैं पर काम नहीं किया लेने के लिए नहीं चाहता था। लेकिन इस तरह आप देखते हैं कि आप यूआरआई को अनुमतियां संलग्न कर सकते हैं।

कैमरा की बात यह है कि मैं इसे क्लिपडेटा के माध्यम से सेट कर सकता हूं और फिर अतिरिक्त अनुमतियां सेट कर सकता हूं। मुझे लगता है कि आपके मामले में आपको केवल FLAG_GRANT_READ_URI_PERMISSION की आवश्यकता है क्योंकि आप किसी ईमेल को फ़ाइल संलग्न कर रहे हैं।

फाइलप्रोवाइडर पर सहायता के लिए link है क्योंकि मैं वहां मिली सारी जानकारी के आधार पर अपनी सभी पोस्ट पर आधारित हूं। हालांकि कैमरा ऐप के लिए पैकेज जानकारी खोजने में कुछ परेशानी थी।

उम्मीद है कि यह मदद करता है।

संबंधित मुद्दे