2013-04-07 6 views
5

मेरा पिछला प्रश्न (Is it possible to share an image on Android via a data URL?) इस प्रश्न से संबंधित है। मैंने यह पता लगाया है कि बाहरी संग्रहण में फ़ाइलों को लिखने की अनुमति के बिना मेरे आवेदन से किसी अन्य एप्लिकेशन को किसी छवि को कैसे साझा किया जाए। हालांकि, मुझे अभी भी कई समस्याएं हैं:जीमेल, फेसबुक, ईरर्नोट इत्यादि को छवि प्रदान करने के लिए सामग्री प्रदाता को कैसे कार्यान्वित करें

  1. जब मैं अपने फोन (एंड्रॉइड 2.2.2) से छवि साझा करने का प्रयास करता हूं, तो प्राप्त करने वाले अनुप्रयोगों में घातक त्रुटियां होती हैं, और वे नहीं आती हैं बिल्कुल छवि के साथ। (क्या यह मेरे ऐप में कुछ ऑपरेशन का परिणाम हो सकता है जो एंड्रॉइड 2.2.2 पर समर्थित नहीं है? या क्या इससे ऐप के बजाय ऐप में कोई त्रुटि आई है?)
  2. जब मैं छवि साझा करने का प्रयास करता हूं Evernote करने के लिए, सब ठीक काम करता है, लेकिन कभी-कभी नोट सहेजने के कुछ सेकंड बाद, मुझे अपने ऐप की स्क्रीन के नीचे एक संदेश मिलता है (Evernote ऐप से): "java.lang.SecurityException: अनुमति अस्वीकार: उद्घाटन प्रदाता com.enigmadream.picturecode.PictureContent ProcessRecord {413db6d0 1872: com.evernote/u0a10105} (pid = 1872, uid = 10105) जो यूआईडी 10104 "
  3. से निर्यात नहीं किया गया है जब मैं तस्वीर को फेसबुक पर साझा करने का प्रयास करता हूं, वहां है तस्वीर के लिए एक आयताकार, लेकिन इसमें कोई तस्वीर नहीं है।

नीचे मेरा ContentProvider कोड है। फ़ाइल-आधारित ContentProvider (विशेष रूप से क्वेरी फ़ंक्शन) को लागू करने का एक आसान और/या अधिक उचित तरीका होना चाहिए। मुझे उम्मीद है कि कई समस्याएं प्रश्न कार्यान्वयन से आती हैं। दिलचस्प बात यह है कि, जीमेल पर जाने पर मेरे नेक्सस 7 पर बहुत अच्छी तरह से काम करता है। यह संलग्नक के लिए भी सही प्रदर्शन नाम और आकार उठाता है।

public class PictureContentProvider extends ContentProvider implements AutoAnimate { 
    public static final Uri CONTENT_URI = Uri.parse("content://com.enigmadream.picturecode.snapshot/picture.png"); 
    private static String[] mimeTypes = {"image/png"}; 
    private Uri generatedUri; 

    @Override 
    public int delete(Uri uri, String selection, String[] selectionArgs) { 
     throw new RuntimeException("PictureContentProvider.delete not supported"); 
    } 

    @Override 
    public String getType(Uri uri) { 
     return "image/png"; 
    } 

    @Override 
    public Uri insert(Uri uri, ContentValues values) { 
     throw new RuntimeException("PictureContentProvider.insert not supported"); 
    } 

    @Override 
    public boolean onCreate() { 
     generatedUri = Uri.EMPTY; 
     return true; 
    } 

    @Override 
    public Cursor query(Uri uri, String[] projection, String selection, 
      String[] selectionArgs, String sortOrder) { 
     long fileSize = 0; 
     MatrixCursor result = new MatrixCursor(projection); 
     File tempFile; 
     try { 
      tempFile = generatePictureFile(uri); 
      fileSize = tempFile.length(); 
     } catch (FileNotFoundException ex) { 
      return result; 
     } 
     Object[] row = new Object[projection.length]; 
     for (int i = 0; i < projection.length; i++) { 

      if (projection[i].compareToIgnoreCase(MediaStore.MediaColumns.DISPLAY_NAME) == 0) { 
      row[i] = getContext().getString(R.string.snapshot_displaystring); 
      } else if (projection[i].compareToIgnoreCase(MediaStore.MediaColumns.SIZE) == 0) { 
      row[i] = fileSize; 
      } else if (projection[i].compareToIgnoreCase(MediaStore.MediaColumns.DATA) == 0) { 
      row[i] = tempFile; 
      } else if (projection[i].compareToIgnoreCase(MediaStore.MediaColumns.MIME_TYPE)==0) { 
      row[i] = "image/png"; 
      } 
     } 

     result.addRow(row); 
     return result; 
    } 

    @Override 
    public int update(Uri uri, ContentValues values, String selection, 
      String[] selectionArgs) { 
     throw new RuntimeException("PictureContentProvider.update not supported"); 
    } 

    @Override 
    public String[] getStreamTypes(Uri uri, String mimeTypeFilter) { 
     return mimeTypes; 
    } 

    private File generatePictureFile(Uri uri) throws FileNotFoundException { 
     if (generatedUri.compareTo(uri)==0) 
      return new File(getContext().getFilesDir(), "picture.png");; 
      Context context = getContext(); 
      String query = uri.getQuery(); 
      String[] queryParts = query.split("&"); 
      String pictureCode = "016OA"; 
      int resolution = 36; 
      int frame = 0; 
      int padding = 0; 
      for (String param : queryParts) { 
      if (param.length() < 2) 
       continue; 
      if (param.substring(0,2).compareToIgnoreCase("p=") == 0) {    
       pictureCode = param.substring(2); 
      } else if (param.substring(0,2).compareToIgnoreCase("r=") == 0) { 
       resolution = Integer.parseInt(param.substring(2));    
      } else if (param.substring(0, 2).compareToIgnoreCase("f=") == 0) { 
       frame = Integer.parseInt(param.substring(2)); 
      } else if (param.substring(0, 2).compareToIgnoreCase("a=") == 0) { 
       padding = Integer.parseInt(param.substring(2)); 
      } 
      } 
      Bitmap picture = RenderPictureCode(pictureCode, resolution, frame, padding); 
      File tempFile = new File(context.getFilesDir(), "picture.png");  
      FileOutputStream stream; 
      stream = new FileOutputStream(tempFile); 
      picture.compress(CompressFormat.PNG, 90, stream); 
      try { 
      stream.flush(); 
      stream.close(); 
      } catch (IOException e) { 
      e.printStackTrace(); 
      throw new Error(e); 
      } 
      picture.recycle(); 
      generatedUri = uri; 
      return tempFile; 
    } 

    @Override 
    public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { 
     File tempFile = generatePictureFile(uri); 
     return ParcelFileDescriptor.open(tempFile, ParcelFileDescriptor.MODE_READ_ONLY); 
    } 
... 
} 

मैं भी <activity> तत्वों का एक भाई के रूप में AndroidManifest.xml फ़ाइल में इस है:

<provider 
     android:name="PictureContentProvider" 
     android:authorities="com.enigmadream.picturecode.snapshot" 
     android:grantUriPermissions="true" 
     android:readPermission="com.enigmadream.picturecode.snapshot" 
     tools:ignore="ExportedContentProvider"> 
     <grant-uri-permission android:path="/picture.png" /> 
    </provider> 

कोड है कि इरादे बनाता है इस तरह दिखता है:

 resolution = mPicView.getWidth(); 
     if (mPicView.getHeight() > resolution) 
      resolution = mPicView.getHeight(); 
     String paddingText = mPadding.getEditableText().toString(); 
     int padding; 
     try { 
      padding = Integer.parseInt(paddingText); 
     } catch (NumberFormatException ex) { 
      padding = 0; 
     } 
     Uri uri = Uri.parse(PictureContentProvider.CONTENT_URI 
      + "?p=" + Uri.encode(mPicView.getPictureCode()) + "&r=" + Integer.toString(resolution) 
      + "&f=" + Integer.toString(mPicView.getFrame()) + "&a=" + Integer.toString(padding)); 
     Intent share = new Intent(Intent.ACTION_SEND); 
     share.setType("image/png"); 
     share.putExtra(Intent.EXTRA_STREAM, uri); 
     share.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.share_subject_made)); 
     share.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 
     startActivity(Intent.createChooser(share, getString(R.id.menu_share))); 

संपादित करें मेरे फोन पर त्रुटि होने पर स्टैक ट्रेस की पहली दो पंक्तियां यहां दी गई हैं:

04-07 13: 56: 24.423: ई/DatabaseUtils (19431): java.lang.SecurityException: अनुमति इनकार: पढ़ने com.enigmadream.picturecode.PictureContentProvider uri सामग्री: //com.enigmadream .picturecode.snapshot/picture.png? p = 01v131 & आर = 36 & च = 0 & एक = 0 पीआईडी ​​से = 19025, uid = 10062 की आवश्यकता है com.enigmadream.picturecode.snapshot

04-07 13 : 56: 24.423: ई/डाटाबेस उपयोग (1 9 431): एंड्रॉइड.content.ContentProvider $ Transport.enforceReadPermission (ContentProvider ।जावा:

<provider 
    android:name="PictureContentProvider" 
    android:authorities="com.enigmadream.picturecode.snapshot" 
    android:grantUriPermissions="true" 
    android:readPermission="com.enigmadream.picturecode.snapshot" 
    tools:ignore="ExportedContentProvider"> 
    <grant-uri-permission android:path="/picture.png" /> 
</provider> 

साथ: 271)

+0

"जब मैं अपने फोन (Android 2.2 से छवि साझा करने के लिए प्रयास करें।2), प्राप्त करने वाले अनुप्रयोगों में घातक त्रुटियां होती हैं, और वे छवि के साथ बिल्कुल नहीं आती हैं "- इनके लिए स्टैक निशान होना चाहिए। जैसा कि मैंने कभी भी सामग्री नहीं देखी है: //' 'उरी' उपयोग क्वेरी पैरामीटर, आप उन्हें हटाने के साथ प्रयोग कर सकते हैं। इसके बजाय एक आरईएसटी-स्टाइल 'उरी' वाक्यविन्यास के साथ जाएं ('content: //com.enigmadream.picturecode.snapshot/p/.../r/.../f/। ../ a /.../ picture.png')। आप अस्थायी रूप से आवश्यक अनुमतियों को अक्षम भी कर सकते हैं और देख सकते हैं कि इससे आपकी समस्या की पहचान करने में मदद मिलती है। – CommonsWare

+0

मुझे नहीं पता कि मैं त्रुटि का एक स्टैक ट्रेस कैसे प्राप्त कर सकता हूं मेरे अपने आवेदन में नहीं हो रहा है। साथ ही, मुझे पता है कि क्वेरी पैरामीटर कुछ परिस्थितियों में काम कर रहे हैं क्योंकि मुझे पैरामीटर के अनुसार उत्पन्न छवियां मिलती हैं। क्या आपको लगता है कि सामग्री यूआरआई में क्वेरी पैरामीटर का उपचार एंड्रॉइड संस्करणों के बीच एक अंतर होगा? , मैंने बस https://en.wikipedia.org/wiki/Representational_state_transfer पर आरईएसटी के अर्थ पर पढ़ा और क्वेरी सेंट के बारे में कुछ भी नहीं देखा अंगूठियां (शब्द क्वेरी उस पृष्ठ पर भी नहीं होती है)। आपका उदाहरण और अधिक "रीस्टफुल" कैसा है? – BlueMonkMN

+0

इसके अलावा, क्या कोई समस्या नहीं होगी यदि मैं पथ में पैरामीटर एम्बेड करने का प्रयास करता हूं जिसमें अनुमतियां सभी अलग-अलग पथों पर लागू नहीं होंगी? – BlueMonkMN

उत्तर

1

मैं अनुमतियाँ मैं कर रहा हूँ या आवश्यकता होती है नहीं कर रहा हूँ या उन्हें

अक्षम करने के तरीके के बजाय ऐसे से परिचित नहीं हूँ

<provider 
    android:name="PictureContentProvider" 
    android:authorities="com.enigmadream.picturecode.snapshot" 
    android:exported="true" 
    tools:ignore="ExportedContentProvider"> 
</provider> 

आपको वास्तव मेंहोना चाहिएपहले में भी, लेकिन अनुमतियों में परिवर्तन मैं android:readPermission और <grant-uri-permissions> को हटाने का प्रतिनिधित्व करता हूं।

फिर, अपने जावा कोड में addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); से छुटकारा पाएं।

यह आपके ContentProvider को विश्व-पढ़ने योग्य बनाने के लिए सेट अप करता है। दीर्घकालिक, यह सही जवाब नहीं हो सकता है। शॉर्ट-टर्म, यह निर्धारित करने में सहायता करेगा कि आपकी एंड्रॉइड 2.2.2 समस्या है क्योंकि FLAG_GRANT_READ_URI_PERMISSION को सम्मानित नहीं किया जा रहा है।

+0

यह परिवर्तन मुझे अपने एंड्रॉइड 2.2 डिवाइस पर जीमेल संदेश के माध्यम से छवि साझा करने की अनुमति देता है। मैं किसी भी कारण से नहीं सोच सकता कि इस एप्लिकेशन को किसी भी सुरक्षा की आवश्यकता होगी। मुझे इसके लिए * किसी भी * अनुमतियों का अनुरोध करने की आवश्यकता नहीं है (यही कारण है कि मुझे इसे जारी रखने में दिलचस्पी थी) इसलिए डिवाइस पर इसका अधिक विशेषाधिकार नहीं है। यह यूआई में दर्ज "कोड" के आधार पर अस्थायी पीएनजी को छोड़कर किसी भी डेटा को सहेजता नहीं है (जो स्रोत कोड की तरह है, सुरक्षा कोड नहीं है)। ऐसा कोई कारण नहीं है कि इसे इस तरह छोड़ दें? फेसबुक अभी भी नहीं दिखाएगा, क्या मुझे इसके बारे में एक अलग प्रश्न या पूछना चाहिए? ...? – BlueMonkMN

+0

@ ब्लूमोन्कएमएन: "किसी भी कारण से इसे छोड़ना नहीं है?" - मेरे पास जवाब देने का कोई अच्छा तरीका नहीं है। यदि आप किसी भी ऐप के साथ किसी भी समय अपने प्रदाता का कोई अनुरोध करने में सहज हैं, तो इसके साथ जाएं। "फेसबुक अभी भी नहीं दिखाएगा" - अगर यह दुर्घटनाग्रस्त हो रहा है, तो स्टैक ट्रेस शायद ऊपर दिए गए "अनुमति अस्वीकार" से अलग है। – CommonsWare

1

मुझे query विधि के कारण कुछ ईमेल और संदेश क्लाइंट्स को साझा करने में समस्याएं थीं। कुछ प्राप्तकर्ता ऐप्स projection पैरामीटर के लिए null में भेजते हैं। जब ऐसा होता है, तो आपका कोड NullPointerException फेंकता है। एनपीई हल करना आसान है। हालांकि, null भेजने वाले ऐप्स को अभी भी कुछ जानकारी की आवश्यकता है। मैं अभी भी फेसबुक पर साझा नहीं कर सकता, लेकिन मैं परीक्षण किए गए सभी अन्य ऐप्स में साझा कर सकता हूं:

EDIT मैं इसे Google Hangout के साथ काम करने के लिए भी नहीं मिल सकता। इसके साथ, कम से कम, मुझे एक टोस्ट मिलता है जो You can't send this file on Hangouts. Try using a picture दर्शाता है। यह प्रश्न भी देखें: Picture got deleted after send via Google hangout। मुझे लगता है कि ऐसा इसलिए है क्योंकि मैं निजी सामग्री का उपयोग कर रहा हूं और Hangouts किसी कारण से इसे स्वीकार नहीं कर सकता/नहीं।

@Override 
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 
     String sortOrder) { 
    if (projection == null) { 
     projection = new String[] { 
       MediaStore.MediaColumns.DISPLAY_NAME, 
       MediaStore.MediaColumns.SIZE, 
       MediaStore.MediaColumns._ID, 
       MediaStore.MediaColumns.MIME_TYPE 
     }; 
    } 

    final long time = System.currentTimeMillis(); 
    MatrixCursor result = new MatrixCursor(projection); 
    final File tempFile = generatePictureFile(uri); 

    Object[] row = new Object[projection.length]; 
    for (int i = 0; i < projection.length; i++) { 

     if (projection[i].compareToIgnoreCase(MediaStore.MediaColumns.DISPLAY_NAME) == 0) { 
      row[i] = uri.getLastPathSegment(); 
     } else if (projection[i].compareToIgnoreCase(MediaStore.MediaColumns.SIZE) == 0) { 
      row[i] = tempFile.length(); 
     } else if (projection[i].compareToIgnoreCase(MediaStore.MediaColumns.DATA) == 0) { 
      row[i] = tempFile; 
     } else if (projection[i].compareToIgnoreCase(MediaStore.MediaColumns.MIME_TYPE)==0) { 
      row[i] = _mimeType; 
     } else if (projection[i].compareToIgnoreCase(MediaStore.MediaColumns.DATE_ADDED)==0 || 
       projection[i].compareToIgnoreCase(MediaStore.MediaColumns.DATE_MODIFIED)==0 || 
       projection[i].compareToIgnoreCase("datetaken")==0) { 
      row[i] = time; 
     } else if (projection[i].compareToIgnoreCase(MediaStore.MediaColumns._ID)==0) { 
      row[i] = 0; 
     } else if (projection[i].compareToIgnoreCase("orientation")==0) { 
      row[i] = "vertical"; 
     } 
    } 

    result.addRow(row); 
    return result; 
} 
0

एक ही समस्या थी और अनुसंधान के बहुत सारे के बाद और यहाँ debuging मेरी 5 सेंट है: (मेरी एंड्रॉयड 2.3.3 और 4.2 उपकरणों पर)

  1. फेसबुक ऐप openFile(Uri uri, String mode) का उपयोग नहीं होगा तो हम पढ़ने के अधिकार के साथ इसे वास्तविक यूआरआई (प्रक्षेपण [i] == MediaStore.MediaColumns.DATA) देना है।
  2. आप अन्यथा अमेरिकन प्लान-एप्लिकेशन सिर्फ repeate जाएगा query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)

यह शायद एक हैक है, और कुछ संवेदनशील डेटा पर काम नहीं होगा, फेसबुक हर प्रक्षेपण यह आपसे पूछता देने के लिए है, लेकिन आप file.setReadable(true, false); कर सकते हैं आंतरिक कोड पर कहीं भी आपके कोड और फेसबुक में आईएमजी देखने और भेजने में सक्षम होंगे। एंड्रॉइड बाहरी भंडारण अनुमतियों की कोई ज़रूरत नहीं है। यदि आईएमजी पठनीय होगा तो सामग्री प्रदाता की कोई आवश्यकता नहीं है। इरादे में सिर्फ लिंक भेज सकते हैं। लेकिन मेरे पास प्रदाता के बिना अजीब google + पूर्वावलोकन व्यवहार था इसलिए इसे रखने का फैसला किया। केवल ट्विटर, एफबी, Google+, स्काइप, जीमेल का परीक्षण और उपयोग करने के लिए बहुत सारे डिवाइस नहीं हैं। अब

यहाँ GitHub Demo है के लिए ठीक काम करता है:

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