ตัวกรองเจตนา Android สำหรับนามสกุลไฟล์เฉพาะหรือไม่


93

ฉันต้องการดาวน์โหลดไฟล์ที่มีนามสกุลเฉพาะจาก 'net และส่งผ่านไปยังแอปพลิเคชันของฉันเพื่อจัดการกับมัน แต่ฉันไม่สามารถหาตัวกรองความตั้งใจได้ ประเภทไฟล์ไม่รวมอยู่ในประเภทไฟล์และฉันลองใช้

<data android:path="*.ext" />

แต่ฉันไม่สามารถทำงานนั้นได้

คำตอบ:


120

นี่คือวิธีที่ฉันกำหนดกิจกรรมของฉันใน AndroidManifest.xml เพื่อให้สิ่งนี้ใช้งานได้

<activity android:name="com.keepassdroid.PasswordActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="file" />
        <data android:mimeType="*/*" />
        <data android:pathPattern=".*\\.kdb" />
        <data android:host="*" />
    </intent-filter>
</activity>

schemeของfileบ่งบอกว่านี่ควรจะเกิดขึ้นเมื่อไฟล์ถูกเปิดท้องถิ่น (แทนที่จะโปรโตคอลเช่น HTTP)

mimeTypeสามารถตั้งค่า*/*ให้ตรงกับประเภทละครใบ้ใดก็ได้

pathPatternเป็นที่ที่คุณระบุส่วนขยายที่คุณต้องการจับคู่ (ในตัวอย่างนี้.kdb) .*ที่จุดเริ่มต้นตรง squence ของตัวละครใด ๆ สตริงเหล่านี้ต้องการการหลีกเลี่ยงสองครั้งดังนั้นจึง\\\\.ตรงกับช่วงเวลาที่แท้จริง จากนั้นปิดท้ายด้วยนามสกุลไฟล์ของคุณ ข้อแม้อย่างหนึ่งของ pathPattern คือนั่น.*ไม่ใช่การจับคู่แบบโลภอย่างที่คุณคาดหวังหากเป็นนิพจน์ทั่วไป รูปแบบนี้จะไม่สามารถจับคู่เส้นทางที่มี.ก่อนหน้า.kdb. หากต้องการทราบรายละเอียดเพิ่มเติมเกี่ยวกับปัญหานี้และวิธีแก้ไขปัญหาโปรดดูที่นี่

สุดท้ายตามเอกสารของ Android จำเป็นต้องใช้ทั้งสองhostและschemeแอตทริบิวต์เพื่อให้pathPatternแอตทริบิวต์ทำงานได้ดังนั้นเพียงตั้งค่าให้สัญลักษณ์แทนเพื่อให้ตรงกับสิ่งใด ๆ

ตอนนี้ถ้าคุณเลือก.kdbไฟล์ในแอพเช่น Linda File Manager แอพของฉันจะแสดงเป็นตัวเลือก ฉันควรทราบว่าสิ่งนี้เพียงอย่างเดียวไม่อนุญาตให้คุณดาวน์โหลดประเภทไฟล์นี้ในเบราว์เซอร์เนื่องจากสิ่งนี้จะลงทะเบียนกับรูปแบบไฟล์เท่านั้น การมีแอปอย่าง Linda File Manager บนโทรศัพท์ของคุณจะเป็นการรีสตาร์ทตัวเองโดยทั่วไปทำให้คุณสามารถดาวน์โหลดไฟล์ประเภทใดก็ได้


3
ที่นี่ใช้ไม่ได้ ก่อนอื่นด้วย mimeType = " " แพ็คเกจไม่ได้ติดตั้งบน Android 2.1 ฉันได้รับ MalformedMimeTypeException การใช้ "* / " แก้ไขปัญหานี้ แต่ตัวกรองนี้ก็ไม่มีผลใด ๆ ฉันกำลังทดสอบกับเบราว์เซอร์ Skyfire ซึ่งไม่ได้รักษาการดาวน์โหลดประเภทละครใบ้ไว้เหมือนที่เบราว์เซอร์ Android มาตรฐานทำ และเมื่อคลิกที่ไฟล์ในรายการดาวน์โหลดของ Skyfire เจตนา VIEW แบบง่ายจะถูกถ่ายทอดพร้อมข้อมูลไฟล์ และตัวกรองความตั้งใจนี้ไม่ตรงกัน
olivierg

@Brian Pellin: ฉันกำลังค้นหาวิธีผูก mime-type กับ.kdbxส่วนขยายเพื่อให้ ES file explorer เปิดไฟล์ kdbx เมื่อฉันถูกชี้ไปที่โพสต์นี้ เห็นได้ชัดว่าหาก Intent มีประเภท MIME ว่างเปล่าตัวกรอง Intent นี้จะไม่ทำงาน !! นอกจากนี้ยังเป็นไปได้ที่จะมี Intent โดยใช้สตริง EMPTY เป็นตัวดำเนินการและเป็นเพียง URI Google เอกสารตอบสนองต่อเจตนานั้นดังนั้นจึงต้องถูกต้อง
billc.cn

2
เพื่อความชัดเจน mimeType ควรเป็น "* / *" ฉันคิดว่าบางคนลืมหนี * s
Brian Pellin

1
ใช้ไม่ได้กับ Android 4 คุณควรใช้กับ<data>แท็กที่มีแอตทริบิวต์ 4 รายการ การมี 4 แท็กนั้นเป็นตรรกะหรือ - ซึ่งใช้ได้กับ Android 2 - แต่ Android 4 นั้นเข้มงวดกว่า ดูstackoverflow.com/questions/20650378/…
Martin

3
ถ้า\\\\.ตรงกับช่วงเวลาตามตัวอักษรทำไมคุณไม่ใช้มันเพื่อสร้าง.kdbส่วนขยายเช่นนี้: \\\\.kdb?
Lealo

37

มีข้อมูลที่ผิดมากมายในหัวข้อนี้ไม่น้อยจากเอกสารของ Google เอง สิ่งที่ดีที่สุดและด้วยตรรกะที่แปลกอาจเป็นไปได้ว่าเอกสารจริงเพียงอย่างเดียวคือซอร์สโค้ด

การใช้ตัวกรองความตั้งใจมีตรรกะที่เกือบจะขัดต่อคำอธิบาย รหัสแยกวิเคราะห์เป็นชิ้นอื่น ๆ ที่เกี่ยวข้องของปริศนา

ตัวกรองต่อไปนี้ค่อนข้างใกล้เคียงกับพฤติกรรมที่สมเหตุสมผล รูปแบบเส้นทางใช้สำหรับความ"file"ตั้งใจของโครงการ

การจับคู่รูปแบบประเภท mime ส่วนกลางจะจับคู่ทุกประเภทตราบเท่าที่นามสกุลไฟล์ตรงกัน สิ่งนี้ไม่สมบูรณ์แบบ แต่เป็นวิธีเดียวที่จะจับคู่ลักษณะการทำงานของตัวจัดการไฟล์เช่น ES File Explorer และ จำกัด เฉพาะ Intent ที่ URI / นามสกุลไฟล์ตรงกัน

ฉันไม่ได้รวมรูปแบบอื่น ๆ เช่น"http"ที่นี่ แต่อาจใช้งานได้ดีกับตัวกรองเหล่านี้ทั้งหมด

โครงร่างแปลก ๆ คือ"content"ส่วนขยายที่ไม่สามารถใช้ได้กับตัวกรอง แต่ตราบใดที่ผู้ให้บริการระบุประเภท MIME ของคุณ (เช่น Gmail จะส่งต่อประเภท MIME สำหรับไฟล์แนบโดยไม่มีข้อ จำกัด ) ตัวกรองจะตรงกัน

Gotchas ที่ต้องระวัง:

  1. โปรดทราบว่าไม่มีสิ่งใดที่ทำงานได้อย่างสม่ำเสมอในตัวกรองมันเป็นกรณีพิเศษที่วกวนและถือว่าละเมิดหลักการที่น่าประหลาดใจอย่างน้อยที่สุดในฐานะเป้าหมายการออกแบบ ไม่มีอัลกอริธึมการจับคู่รูปแบบใดที่เป็นไปตามไวยากรณ์หรือลักษณะการทำงานเดียวกัน การไม่มีฟิลด์บางครั้งอาจเป็นสัญลักษณ์แทนและบางครั้งก็ไม่ใช่ แอตทริบิวต์ภายในองค์ประกอบข้อมูลบางครั้งต้องไปด้วยกันและบางครั้งก็ละเว้นการจัดกลุ่ม มันน่าจะทำได้ดีกว่านี้จริงๆ
  2. schemeและhostจะต้องมีการระบุไว้สำหรับpathกฎระเบียบในการแข่งขัน (ตรงกันข้ามกับคู่มือ API ของ Google ในปัจจุบัน)
  3. อย่างน้อย ES File Explorer จะสร้าง Intent ด้วยประเภท MIME ""ซึ่งถูกกรองแตกต่างกันมากจนnullไม่สามารถจับคู่ได้อย่างชัดเจนและสามารถจับคู่ได้โดย"*/*"ตัวกรองที่มีความเสี่ยงเท่านั้น
  4. "*/*"กรองจะไม่ตรงกับเจตจำนงกับnullชนิดไมม์ - ที่ต้องมีการกรองแยกต่างหากสำหรับกรณีนี้โดยเฉพาะไม่มีชนิดไมม์ที่ทั้งหมด
  5. "content"โครงการเท่านั้นที่สามารถจับคู่โดยชนิดไมม์เพราะชื่อไฟล์เดิมไม่สามารถใช้ได้ในเจตนา (อย่างน้อยกับ Gmail)
  6. การจัดกลุ่มแอตทริบิวต์ใน"data"องค์ประกอบที่แยกจากกันนั้น (เกือบ) ไม่เกี่ยวข้องกับการตีความโดยมีข้อยกเว้นเฉพาะhostและport- ซึ่งจับคู่กัน อย่างอื่นไม่มีการเชื่อมโยงเฉพาะภายใน"data"องค์ประกอบหรือระหว่าง"data"องค์ประกอบ

เมื่อคำนึงถึงสิ่งเหล่านี้แล้วนี่คือตัวอย่างพร้อมความคิดเห็น:

<!--
     Capture content by MIME type, which is how Gmail broadcasts
     attachment open requests.  pathPattern and file extensions
     are ignored, so the MIME type *MUST* be explicit, otherwise
     we will match absolutely every file opened.
-->
<intent-filter
    android:icon="@drawable/icon"
    android:label="@string/app_name"
    android:priority="50" >
    <action android:name="android.intent.action.VIEW" />

    <category android:name="android.intent.category.BROWSABLE" />
    <category android:name="android.intent.category.DEFAULT" />

    <data android:scheme="file" />
    <data android:scheme="content" />
    <data android:mimeType="application/vnd.my-type" />
</intent-filter>

<!--
     Capture file open requests (pathPattern is honoured) where no
     MIME type is provided in the Intent.  An Intent with a null
     MIME type will never be matched by a filter with a set MIME
     type, so we need a second intent-filter if we wish to also
     match files with this extension and a non-null MIME type
     (even if it is non-null but zero length).
-->
<intent-filter
    android:icon="@drawable/icon"
    android:label="@string/app_name"
    android:priority="50" >
    <action android:name="android.intent.action.VIEW" />

    <category android:name="android.intent.category.BROWSABLE" />
    <category android:name="android.intent.category.DEFAULT" />

    <data android:scheme="file" />
    <data android:host="*" />

    <!--
         Work around Android's ugly primitive PatternMatcher
         implementation that can't cope with finding a . early in
         the path unless it's explicitly matched.
    -->
    <data android:pathPattern=".*\\.my-ext" />
    <data android:pathPattern=".*\\..*\\.my-ext" />
    <data android:pathPattern=".*\\..*\\..*\\.my-ext" />
    <data android:pathPattern=".*\\..*\\..*\\..*\\.my-ext" />
    <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.my-ext" />
    <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.my-ext" />
    <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.my-ext" />
</intent-filter>

<!--
     Capture file open requests (pathPattern is honoured) where a
     (possibly blank) MIME type is provided in the Intent.  This
     filter may only be necessary for supporting ES File Explorer,
     which has the probably buggy behaviour of using an Intent
     with a MIME type that is set but zero-length.  It's
     impossible to match such a type except by using a global
     wildcard.
-->
<intent-filter
    android:icon="@drawable/icon"
    android:label="@string/app_name"
    android:priority="50" >
    <action android:name="android.intent.action.VIEW" />

    <category android:name="android.intent.category.BROWSABLE" />
    <category android:name="android.intent.category.DEFAULT" />

    <data android:scheme="file" />
    <data android:host="*" />
    <data android:mimeType="*/*" />

    <!--
         Work around Android's ugly primitive PatternMatcher
         implementation that can't cope with finding a . early in
         the path unless it's explicitly matched.
    -->
    <data android:pathPattern=".*\\.my-ext" />
    <data android:pathPattern=".*\\..*\\.my-ext" />
    <data android:pathPattern=".*\\..*\\..*\\.my-ext" />
    <data android:pathPattern=".*\\..*\\..*\\..*\\.my-ext" />
    <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.my-ext" />
    <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.my-ext" />
    <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.my-ext" />
</intent-filter>

เยี่ยมมากที่คุณยืนหยัดกับความต้องการ \\ .. ซ้ำแล้วซ้ำเล่าและนิสัยใจคออื่น ๆ Google ควรแก้ไขสิ่งนี้ภายใน 4.2 สิ่งที่เป็นบ้า อนิจจาฉันยังมีกรณีที่ตัวอย่างของคุณดูเหมือนจะแก้ไขไม่ได้ มีปัญหาบางอย่างกับส่วนขยาย 6 cha เช่น ".gblorb" ที่รหัสของฉันทำงานได้ดีโดยใช้ตัวอักษร 3 ตัวหรือน้อยกว่าหรือไม่
RoundSparrow hilltx

คำตอบที่ดีที่สุดสำหรับคำถามนี้และคำถามที่คล้ายกันในความคิดของฉัน! น่าเศร้าตราบใดที่ไม่สามารถจับคู่ความตั้งใจของเนื้อหาตามนามสกุลไฟล์ได้ (ตามที่คุณระบุไว้ในข้อ 5) คุณจะไม่สามารถกรอง Intent ที่ถูกต้องทั้งหมดได้อย่างน่าเชื่อถือโดยไม่ต้องจับคู่เจตนาที่ผิด นี่เป็นกรณีที่คุณไม่สามารถใช้ประเภทละครใบ้ที่กำหนดเองได้ ตราบใดที่ Android ไม่มีวิธีแก้ปัญหานี้มันจะเป็นตัวเลือกไฟล์ภายในแอพให้ฉัน ... ฉันไม่อยากทำให้ผู้ใช้สับสนกับพฤติกรรมที่ไม่สอดคล้องกัน
Benjamin Bisinger

1
ขอบคุณมาก .. คุณทำให้วันของฉันเป็นแบบนี้ .. ในกรณีของฉันฉันต้องเปลี่ยน MimeType เหมือน <data android:mimeType="*/*" /> ทั้งสามตัวเลือกและมันก็ใช้งานได้ดีสำหรับทุกแอปรวมถึง Google Drive และ Gmail
Rishabh Wadhwa

1
ฉันอยากจะขอบคุณมาก @David Sainty คุณหมดสิ้นความทุกข์ทรมานที่ยาวนาน 24 ชั่วโมงของฉันในการพยายามหาวิธีจัดการกับมัน ฉันลองใช้stackoverflow.com/q/18577860/6110285 , stackoverflow.com/a/8599921/6110285และอื่น ๆ อีกมากมายซึ่งคล้ายกัน อันนี้คนเดียวที่ใช้ได้
pittix

24

ฉันต้องยอมรับว่างานง่าย ๆ ในการเปิดไฟล์แนบจากอีเมลและไฟล์จากระบบไฟล์บน Android เป็นหนึ่งในประสบการณ์ที่น่าตื่นเต้นกว่าที่เคยมีมา ง่ายต่อการจัดการไฟล์จำนวนมากเกินไปหรือน้อยเกินไป แต่การทำให้ถูกต้องเป็นเรื่องยาก วิธีแก้ปัญหาส่วนใหญ่ที่โพสต์บน stackoverflow ทำงานไม่ถูกต้องสำหรับฉัน

ความต้องการของฉันคือ:

  • ให้แอปของฉันจัดการกับไฟล์แนบที่แอปของฉันแชร์
  • ให้แอปของฉันจัดการไฟล์ในที่เก็บไฟล์ที่แอปของฉันสร้างขึ้นและมีนามสกุลเฉพาะ

วิธีที่ดีที่สุดในการทำงานนี้คือการระบุประเภท MIME ที่กำหนดเองสำหรับไฟล์แนบของคุณ และคุณอาจเลือกที่จะมีนามสกุลไฟล์ที่กำหนดเอง สมมติว่าแอปของเรามีชื่อว่า "Cool App" และเราสร้างไฟล์แนบที่มี ".cool" ต่อท้าย

นี่เป็นสิ่งที่ใกล้เคียงที่สุดที่ฉันไปถึงเป้าหมายและมันได้ผล ... น่าพอใจ

<!-- Register to handle email attachments -->
<!-- WARNING: Do NOT use android:host="*" for these as they will not work properly -->
<intent-filter>
    <!-- needed for properly formatted email messages -->
    <data
        android:scheme="content"
        android:mimeType="application/vnd.coolapp"
        android:pathPattern=".*\\.cool" />
    <!-- needed for mangled email messages -->
    <data
        android:scheme="content"
        android:mimeType="application/coolapp"
        android:pathPattern=".*\\.cool" />
    <!-- needed for mangled email messages -->
    <data
        android:scheme="content"
        android:mimeType="application/octet-stream"
        android:pathPattern=".*\\.cool" />

    <action android:name="android.intent.action.VIEW" />

    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
</intent-filter>

<!-- Register to handle file opening -->
<intent-filter>
    <data android:scheme="file"
          android:mimeType="*/*"
          android:pathPattern=".*\\.cool"
          android:host="*"/>

    <action android:name="android.intent.action.VIEW" />

    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
</intent-filter>

หมายเหตุ:

  • pathPatternดูเหมือนว่าจะมากหรือน้อยละเว้นสำหรับสิ่งที่แนบมา (เมื่อใช้android:scheme="content") หากใครสักคนได้รับ pathPattern เพื่อตอบสนองต่อรูปแบบบางอย่างเท่านั้นฉันจะตื่นเต้นที่จะได้เห็นวิธีการ
  • แอป Gmail ปฏิเสธที่จะแสดงรายการแอปของฉันในตัวเลือกหากฉันเพิ่มandroid:host="*"แอตทริบิวต์
  • อาจยังใช้งานได้หากintent-filterรวมบล็อกเหล่านี้แต่ฉันยังไม่ได้ตรวจสอบ
  • ในการจัดการคำขอจากเบราว์เซอร์เมื่อดาวน์โหลดไฟล์android:scheme="http"สามารถใช้ได้ โปรดทราบว่าเบราว์เซอร์บางอย่างอาจเลอะandroid:mimeTypeเพื่อให้การทดสอบกับandroid:mimeType="*/*"และตรวจสอบในการดีบักสิ่งที่จะถูกส่งผ่านจริงแล้วกระชับกรองที่จะไม่จบลงด้วยการที่แอปที่น่ารำคาญที่จับทุกอย่าง
  • นักสำรวจไฟล์บางคนจะทำให้ประเภท MIME สำหรับไฟล์ของคุณเสียหายเช่นกัน ข้างต้นintent-filterได้รับการทดสอบด้วยแอป "ไฟล์ของฉัน" ของ Samsung บน Galaxy S3 FX Explorer ยังคงปฏิเสธที่จะเปิดไฟล์อย่างถูกต้องและฉันก็สังเกตว่าไม่มีการใช้ไอคอนแอพสำหรับไฟล์ อีกครั้งหากใครได้รับผลงานโปรดแสดงความคิดเห็นด้านล่าง

ฉันหวังว่าคุณจะพบว่าสิ่งนี้มีประโยชน์และคุณจะไม่ต้องเสียเวลาไปกับการผสมผสานที่เป็นไปได้ทั้งหมด มีพื้นที่สำหรับการปรับปรุงดังนั้นยินดีรับฟังความคิดเห็น


นี่เป็นวิธีแก้ปัญหาที่ใช้ได้ผลสำหรับฉัน การลงทะเบียน <intent-filter> แยกต่างหากสำหรับ Content-Scheme และ File-Scheme ได้เคล็ดลับ! ขอบคุณ!
Mehlyfication

ขอบคุณ! ทำงานให้ฉัน ทั้งแอพ Gmail และแอพ Samsung My Files บน Galaxy S6 สามารถเปิดไฟล์ด้วยแอพของฉันโดยใช้โซลูชันของคุณ!
Haris

"ชื่อแอป" คืออะไร (ในกรณีของฉันชื่อแอปที่มนุษย์อ่านได้จะมีช่องว่างอยู่)
William Jockusch

@WilliamJockusch ดูเหมือนว่า @DavidSainty จะเก็บชื่อแอปพลิเคชันไว้ในไฟล์ทรัพยากรสตริง ช่องว่างควรจะใช้ได้ สตริงที่ใช้สำหรับandroid:labelตัวกรองความตั้งใจคือสตริงที่ผู้ใช้จะเห็นในเมนูตัวเลือก โดยใช้ชื่อแอปพลิเคชันเริ่มต้น
omahena

ฉันควรใช้อะไรสำหรับแอป "Google ไดรฟ์"
นักพัฒนา Android

9

คำตอบของ Brian ข้างต้นทำให้ฉันได้ 90% ไปที่นั่น เพื่อจบมันออกสำหรับประเภทละครใบ้ที่ฉันใช้

android:mimeType="*/*"

ฉันสงสัยว่าผู้โพสต์ก่อนหน้านี้พยายามโพสต์รายละเอียดแบบเดียวกัน แต่ถ้าขาดการใช้สตาร์สแลชสตาร์เป็นโค้ดแล้วการสแต็กโอเวอร์โฟลว์ก็แสดงให้เห็นว่ามันเป็นเพียงเครื่องหมายทับ


2
ด้วยวิธีนี้คุณจะจัดการไฟล์ทุกประเภทและมันน่ารำคาญจริงๆ (ยกเว้นว่าแอปของคุณจัดการทุกอย่าง) ...
Tim Autin

นี้ไม่ดี. โปรดอย่าทำสิ่งนี้ภายในแอปของคุณ
อังคาร

8

แทนที่จะandroid:pathลองandroid:mimeTypeใช้ค่าประเภท MIME ของเนื้อหาชิ้นนี้ นอกจากนี้android:pathไม่ยอมรับสัญลักษณ์แทน - ใช้android:pathPatternสำหรับสิ่งนั้น


"ประเภทไฟล์ไม่รวมอยู่ใน mimetypes"? ยังคงมีประเภทของเนื้อหาที่คุณกำลังดาวน์โหลดอยู่แม้ว่าจะไม่ได้ใช้คำเดียวกันก็ตาม
Eric Mill

ประเภทของเนื้อหามีประเภท mimetype แต่ไฟล์นั้นสร้างขึ้นโดยแอปพลิเคชันของบุคคลที่สามซึ่งใส่นามสกุลที่แตกต่างออกไปดังนั้นฉันไม่คิดว่ามันจะถูกจดจำว่าเป็นประเภท mimetype นั้น
Curyous

7

ฉันพยายามทำให้สิ่งนี้ใช้งานได้มานานแล้วและได้ลองใช้วิธีแก้ปัญหาที่แนะนำทั้งหมดโดยพื้นฐานแล้วและยังไม่สามารถให้ Android จดจำนามสกุลไฟล์เฉพาะได้ ฉันมีตัวกรองความตั้งใจด้วย"*/*"mimetype ซึ่งเป็นสิ่งเดียวที่ดูเหมือนว่าจะใช้งานได้และตอนนี้เบราว์เซอร์ไฟล์แสดงรายการแอปของฉันเป็นตัวเลือกสำหรับการเปิดไฟล์อย่างไรก็ตามแอปของฉันแสดงเป็นตัวเลือกสำหรับการเปิดไฟล์ประเภทใดก็ได้แม้ว่า ฉันได้ระบุนามสกุลไฟล์โดยใช้แท็ก pathPattern สิ่งนี้ไปได้ไกลถึงแม้ในขณะที่ฉันพยายามดู / แก้ไขผู้ติดต่อในรายชื่อผู้ติดต่อของฉัน Android จะถามฉันว่าฉันต้องการใช้แอพของฉันเพื่อดูผู้ติดต่อหรือไม่และนั่นเป็นเพียงหนึ่งในหลาย ๆ สถานการณ์ที่เกิดเหตุการณ์นี้ขึ้นซึ่งน่ารำคาญมาก

ในที่สุดฉันก็พบว่ากลุ่ม Google นี้โพสต์พร้อมคำถามที่คล้ายกันซึ่งวิศวกรกรอบงาน Android ตอบกลับ เธออธิบายว่า Android ไม่รู้อะไรเลยเกี่ยวกับนามสกุลไฟล์มีเพียงประเภท MIME เท่านั้น ( https://groups.google.com/forum/#!topic/android-developers/a7qsSl3vQq0 )

ดังนั้นจากสิ่งที่ฉันได้เห็นลองและอ่าน Android ไม่สามารถแยกความแตกต่างระหว่างนามสกุลไฟล์และแท็ก pathPattern ได้โดยพื้นฐานแล้วเป็นการเสียเวลาและพลังงานอย่างมาก หากคุณโชคดีพอที่ต้องการเพียงไฟล์ประเภทละครใบ้บางประเภท (เช่นข้อความวิดีโอหรือเสียง) คุณสามารถใช้ตัวกรองความตั้งใจกับประเภทละครใบ้ หากคุณต้องการนามสกุลไฟล์เฉพาะหรือประเภทละครใบ้ที่ Android ไม่รู้จักอย่างไรก็ตามคุณก็โชคไม่ดี

หากฉันผิดเกี่ยวกับสิ่งนี้โปรดบอกฉันจนถึงตอนนี้ฉันได้อ่านทุกโพสต์และลองใช้วิธีแก้ปัญหาที่เสนอทั้งหมดที่ฉันพบ แต่ไม่มีใครได้ผล

ฉันสามารถเขียนอีกหนึ่งหน้าหรือสองหน้าเกี่ยวกับความธรรมดาของสิ่งต่างๆเหล่านี้ใน Android และประสบการณ์ของนักพัฒนาซอฟต์แวร์ที่แย่ลง แต่ฉันจะช่วยคุณไม่ให้โกรธ;) หวังว่าฉันจะช่วยใครบางคนได้


1
โหวตให้คุณเนื่องจากคำตอบของคุณให้ลิงค์ที่เป็นประโยชน์และผู้โหวตไม่ได้แสดงความคิดเห็น ขออภัย SO อาจไม่เป็นมิตรในบางครั้ง แต่อย่าเลิกกับมัน
John Hatton

4

อัปเดตปี 2020

Android ได้เปลี่ยนไปใช้ URI ของเนื้อหาและประเภท MIME สำหรับตัวกรองความตั้งใจ

ปัญหา

URI เนื้อหาไม่จำเป็นต้องมีนามสกุลหรือชื่อของไฟล์และจะแตกต่างกันระหว่างแอปพลิเคชันต่างๆที่ให้เนื้อหา / ไฟล์

ต่อไปนี้เป็นตัวอย่าง URI ของเนื้อหาจากแอปพลิเคชันอีเมลที่แตกต่างกันสำหรับไฟล์แนบอีเมลเดียวกัน :

Gmail -> content://com.google.android.gm.sapi/some_email@gmail.com/message_attachment_external/%23thread-a%3Ar332738858767305663/%23msg-a%3Ar-5439466788231005876/0.1?account_type=com.google&mimeType=application%2Foctet-stream&rendition=1

Outlook -> content://com.microsoft.office.outlook.fileprovider/outlookfile/data/data/com.microsoft.office.outlook/cache/file-download/file--2146063402/filename.customextention

แอพ Samsung Email -> content://com.samsung.android.email.attachmentprovider/1/1/RAW

ดังที่เห็นได้ว่าแตกต่างกันและไม่รับประกันว่าจะมีสิ่งที่เกี่ยวข้องกับไฟล์จริงของคุณ ดังนั้นคุณไม่สามารถใช้ไฟล์android:pathPatternเหมือนที่แนะนำมากที่สุด

วิธีแก้ปัญหาสำหรับไฟล์แนบอีเมล

<intent-filter>
    <action android:name="android.intent.action.VIEW"/>

    <category android:name="android.intent.category.BROWSABLE"/>
    <category android:name="android.intent.category.DEFAULT"/>

    <data android:scheme="content"/>
    <data android:host="*"/>

    <!--  Required for Gmail and Samsung Email App  -->
    <data android:mimeType="application/octet-stream"/>

    <!--  Required for Outlook  -->
    <data android:mimeType="application/my-custom-extension"/>
</intent-filter>

จากการทดสอบฉันพบ MIME-types ที่ Gmail, Outlook และ Samsung Email ใช้และเพิ่มสิ่งเหล่านั้นลงในตัวกรองความตั้งใจของฉัน

คำเตือน / Gotchas

  • ฉันพบว่าด้วยวิธีแก้ปัญหาข้างต้นของฉันหากฉันเปิดไฟล์ใด ๆ ที่เป็นประเภทไบนารีไฟล์นั้นจะเปิดแอปของฉันโดยอัตโนมัติ ฉันจัดการสิ่งนี้ในกิจกรรมของฉันโดยแสดงสถานะล้มเหลวหากเราไม่สามารถแยกวิเคราะห์ไฟล์ได้ ฉันคิดว่านี่เป็นเหตุการณ์ที่ค่อนข้างหายากดังนั้นจึงเป็นเรื่องที่ยอมรับได้

  • ฉันไม่พบวิธีใด ๆ ในการเปิดแอปของฉันผ่านเบราว์เซอร์ไฟล์โดยไม่ต้องเพิ่ม<data android:mimeType="*/*"/>ตัวกรองความตั้งใจของฉัน ฉันไม่สามารถใช้สิ่งนี้ได้เพราะมันจะเปิดแอปของฉันทุกครั้งที่ผู้ใช้คลิกไฟล์ใด ๆบนโทรศัพท์ของพวกเขา (ไม่ใช่แค่ไฟล์นามสกุลที่กำหนดเอง) ฉันไม่แนะนำให้เพิ่มสิ่งนี้ในตัวกรองความตั้งใจของคุณ

ความคิดสุดท้าย

  • ขณะนี้ยังไม่มีโซลูชันที่ยอดเยี่ยมสำหรับการเชื่อมโยงแอปของคุณกับประเภทส่วนขยายเฉพาะใน Android นี่เป็นสิ่งที่ดีที่สุดที่ฉันสามารถทำได้ในสถานการณ์ของฉัน

ขอบคุณมากมันใช้งานได้ทดสอบเมื่อ ต.ค. 2020 จาก android 7
Harsh

3

คำตอบของ Brian นั้นใกล้เคียงมาก แต่นี่เป็นวิธีที่สะอาดและปราศจากข้อผิดพลาดในการเรียกใช้แอปของคุณเมื่อพยายามเปิดไฟล์ที่มีนามสกุลที่คุณกำหนดเอง (ไม่จำเป็นต้องมีแบบแผนหรือโฮสต์):

<intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:mimeType="*/*" />
    <data android:pathPattern="*.*\\.kdb" />
</intent-filter>

2
เอกสารของ Android ระบุว่าแอตทริบิวต์ pathPattern มีความหมายก็ต่อเมื่อมีการระบุรูปแบบและโฮสต์และฉันได้ตรวจสอบแล้ว: developer.android.com/guide/topics/manifest/data-element.html
Brian Pellin

4
-1; สิ่งนี้จะตรงกับไฟล์ใด ๆ ความคิดเห็นของ Brian ถูกต้องและด้วยการปรับเปลี่ยน mimeType = " / " ตัวอย่างเดิมของเขาจึงสมบูรณ์แบบ
Nick

โพสต์นี้ถ้านานมาแล้ว แต่ไม่มี "/" ไม่ติดตั้ง คุณต้องใช้ "* / *" ซึ่งจะตรงกับประเภทไฟล์ใด ๆ (ไม่แน่ใจว่าคุณตั้งใจจะพูดแบบนี้หรือไม่) ดังนั้นโปรแกรมของคุณอาจถูกขอให้เปิดวิดีโอหรือ mp3 ฉันยังไม่พบวิธีแก้ปัญหานี้
Rene

คุณควรใช้<data>แท็กเดียวที่มีแอตทริบิวต์สี่รายการ โซลูชันของคุณอาจใช้ได้กับ Android 2 - แต่กฎต่างๆเข้มงวดมากขึ้น: stackoverflow.com/questions/20650378/…
Martin

เกิดอะไรขึ้นกับเส้นทางแปลก ๆรูปแบบ ? และhostและschemeจะต้อง!
IgorGanapolsky

3

ใน Android 4 กฎนั้นเข้มงวดมากขึ้นกว่าที่เคยเป็นมา ใช้:

    <data
      android:host=""
      android:mimeType="*/*"
      android:pathPattern=".*\\.ext"
      android:scheme="file"
    ></data>

3

ฉันเคยดิ้นรนกับเรื่องนี้มาพอสมควรสำหรับนามสกุลไฟล์ที่กำหนดเองด้วยตัวเอง หลังจากค้นหาเป็นจำนวนมากฉันพบหน้าเว็บนี้ซึ่งผู้โพสต์พบว่าคลาส patternMatcher ของ Android (ซึ่งใช้สำหรับการจับคู่ pathPattern ใน Intent-Filters) มีพฤติกรรมที่ไม่คาดคิดเมื่อเส้นทางของคุณมีอักขระตัวแรกของรูปแบบการจับคู่ของคุณที่อื่นในเส้นทาง (เช่นถ้าคุณพยายามจับคู่ "* .xyz" คลาส patternMatcher จะหยุดหากมี "x" อยู่ก่อนหน้าในเส้นทางของคุณ) นี่คือสิ่งที่เขาพบสำหรับวิธีแก้ปัญหาและทำงานให้ฉันแม้ว่ามันจะเป็นการแฮ็กเล็กน้อย:

PatternMatcher ใช้สำหรับ pathPattern ที่ IntentFilter แต่อัลกอริทึมของ PatternMatcher ค่อนข้างแปลกสำหรับฉัน นี่คืออัลกอริทึมของ Android PatternMatcher

หากมีรูปแบบ 'อักขระถัดไป' ของ '. *' อยู่ตรงกลางของสตริง PatternMatcher จะหยุดการวนซ้ำที่จุดนั้น (ดู PatternMatcher.java ของกรอบงาน Android)

เช่น สตริง: "this is a attachment" pattern: ". att. " Android PatternMatcher ป้อนลูปเพื่อจับคู่ ' 'รูปแบบจนกว่าจะพบกับอักขระถัดไปของรูปแบบ (ในตัวอย่างนี้' a ') So,' 'การจับคู่วนหยุดที่ดัชนี 8 -' a 'ระหว่าง' คือ 'และ' ของฉัน ' ดังนั้นผลลัพธ์ของการจับคู่นี้จะคืนค่าเป็น "เท็จ"

ค่อนข้างแปลกไม่ใช่เหรอ ในการแก้ปัญหานี้ - ลดความเป็นไปได้จริง - นักพัฒนาควรใช้ pathPattern ที่น่ารำคาญ

เช่น เป้าหมาย: จับคู่เส้นทาง uri ซึ่งรวมถึง "ข้อความ"

<intent-filter>
...
<data android:pathPattern=".*message.*" />
<data android:pathPattern=".*m.*message.*" />
<data android:pathPattern=".*m.*m.*message.*" />
<data android:pathPattern=".*m.*m.*m.*message.*" />
<data android:pathPattern=".*m.*m.*m.*m.*message.*" />
...
</intent-filter>

โดยเฉพาะเมื่อจับคู่กับนามสกุลไฟล์ที่กำหนดเอง


สำหรับทุกคนที่สนใจสามารถบันทึกปัญหาได้ที่code.google.com
benjamin davis

3

ไม่มีสิ่งใดที่ทำงานได้อย่างถูกต้องสำหรับการดำเนินการ VIEW หรือ SEND หากคำต่อท้ายไม่ได้ลงทะเบียนด้วยประเภท MIME ในระบบของ Android = ฐานข้อมูล MIME แบบกว้าง การตั้งค่าเดียวที่ฉันพบว่าไฟสำหรับคำต่อท้ายที่ระบุรวมถึงandroid:mimeType="*/*"แต่การดำเนินการจะเริ่มทำงานสำหรับไฟล์ทั้งหมด ไม่ใช่สิ่งที่คุณต้องการอย่างชัดเจน!

ฉันไม่พบวิธีแก้ปัญหาที่เหมาะสมโดยไม่ต้องเพิ่ม mime และคำต่อท้ายในฐานข้อมูล mime ของ Android จนถึงตอนนี้ฉันยังไม่พบวิธีที่จะทำเช่นนั้น ถ้าใครรู้ตัวชี้จะยอดเยี่ยม


2

เมื่อเจตจำนงเป็นintent-filterไปตามintent-filterข้อกำหนดข้อกำหนดเหล่านี้คือ: (ลองนึกภาพรายการตรวจสอบ)

  • การจับคู่ใด ๆ <action>
  • การจับคู่ใด ๆ <category>
  • การจับคู่ใด ๆ<data mimeType>(แก้ไขอย่างง่าย: " / ")
  • ทางเลือก:

    • ใด ๆ การจับคู่<data scheme>(แก้ไขได้ง่าย: <data android:scheme="file" /> <data android:scheme="content" />)

    • การจับคู่ใด ๆ<data host>(แก้ไขง่าย: "*")

    • การจับคู่ใด ๆ<data pathPattern/etc.>(ตัวอย่างเช่น.*\\.0cc)

การกำหนด<data $type="">องค์ประกอบหลายรายการทำเครื่องหมายในช่อง $ type iff ใด ๆ ที่<data $type=>ตรงกับIntent .

การละเว้น mimeType จะทำให้คุณเสียหายintent-filterแม้ว่าจะดูเหมือนซ้ำซ้อน การละเว้น<data scheme/host/pathPattern>ทำให้ตัวกรองของคุณตรงกับทุกอย่าง

https://f-droid.org/en/packages/de.k3b.android.intentintercept/เป็นแอปที่ออกแบบมาเพื่อรับIntent ทั้งหมดและช่วยให้คุณตรวจสอบเจตนาได้ application/octet-streamผมได้เรียนรู้ว่านามสกุลไฟล์ที่ไม่รู้จักเปิดผ่านผู้จัดการไฟล์แบบง่ายจะถูกส่งกับชนิดไมม์

https://stackoverflow.com/a/4621284/2683842รายงานว่า<data pathPattern=> .*xyzถูกยกเลิกในครั้งแรกที่เห็นและจะล้มเหลวทันทีถ้าไม่ได้ตามมาด้วยx yzดังนั้น/sdcard/.hidden/foo.0ccจะไม่ผ่าน.*\\.0ccเว้นแต่คุณจะพยายาม.*\\..*\\.0ccแทน

  • ฉันไม่ได้ตรวจสอบว่าวิธีแก้ปัญหานี้จำเป็นหรือไม่

ผลลัพธ์สุดท้าย:

<activity android:name=".Ft2NsfActivity">

    <intent-filter>
        <action android:name="android.intent.action.VIEW" />

        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />

        <data android:scheme="file" />
        <data android:scheme="content" />
        <data android:host="*" />
        <data android:pathPattern=".*\\.ftm"/>
        <data android:pathPattern=".*\\..*\\.ftm"/>
        <data android:pathPattern=".*\\..*\\..*\\.ftm"/>
        <data android:pathPattern=".*\\..*\\..*\\..*\\.ftm"/>
        <data android:pathPattern=".*\\.0cc"/>
        <data android:pathPattern=".*\\..*\\.0cc"/>
        <data android:pathPattern=".*\\..*\\..*\\.0cc"/>
        <data android:pathPattern=".*\\..*\\..*\\..*\\.0cc"/>
        <data android:mimeType="*/*" />
    </intent-filter>

</activity>

1

หากคุณต้องการให้เปิดไฟล์โดยตรงจาก Gmail, ดรอปบ็อกซ์หรือเครื่องมือสร้างไฟล์ Android ใด ๆ ให้ใช้รหัสต่อไปนี้ (ลบ 'android: host = "*"' ที่ทำให้ไม่สามารถเข้าถึงไฟล์สำหรับ gmail ได้):

<intent-filter>
    <action android:name="android.intent.action.VIEW"/>
    <category android:name="android.intent.category.BROWSABLE"/>
    <category android:name="android.intent.category.DEFAULT"/>
    <data android:scheme="content" android:pathPattern=".*\\.kdb" 
          android:mimeType="application/octet-stream"/>


</intent-filter>

<intent-filter>
    <action android:name="android.intent.action.VIEW"/>
    <category android:name="android.intent.category.DEFAULT"/>
    <data android:scheme="file" android:mimeType="*/*"     
          android:pathPattern=".*\\.kdb"/>
</intent-filter>

ต้องเขียนตัวกรองข้อมูลในหนึ่งคำสั่งตาม Android เวอร์ชัน 4.x


ฉันพยายามทุกอย่างเพื่อให้การดาวน์โหลดและเปิดเบราว์เซอร์ Android ทำงานได้อย่างถูกต้อง โซลูชันของคุณใช้งานได้ดีกับเบราว์เซอร์ดั้งเดิมของ Android และ android chrome แต่ android firefox ดูเหมือนว่าจะเปิดไฟล์ของฉันในหน้าต่างข้อความ เป็นประเภทละครใบ้ที่กำหนดเองและส่วนขยายที่กำหนดเอง ก่อนหน้านี้มีเพียงส่วนขยายเท่านั้นที่ใช้งานได้ใน firefox ตอนนี้ใช้งานได้ทุกที่ยกเว้น firefox (รวมถึง gmail) ฉันยังคงทดสอบอยู่ แต่ฉันแค่อยากจะแจ้งว่ามีปัญหาข้ามเบราว์เซอร์ชุดใหม่ที่นี่
Damon Smith

1

ใช้ตัวกรองด้านล่างเพื่อเปิดจากเบราว์เซอร์ gmail และไฟล์เบราว์เซอร์ (ทดสอบแล้ว) หมายเหตุ: โปรดอย่าผสานสองตัวกรองซึ่งจะทำให้เบราว์เซอร์ละเว้นแอปของคุณ (ทดสอบแล้ว)

        <intent-filter>
            <action android:name="android.intent.action.VIEW"/>
            <category android:name="android.intent.category.DEFAULT"/>
            <category android:name="android.intent.category.BROWSABLE"/>

            <data android:scheme="file" android:pathPattern=".*\\.ext" android:mimeType="application/*"/>
            <data android:scheme="content" android:pathPattern=".*\\.ext" android:mimeType="application/*"/>
        </intent-filter>

        <intent-filter>
                <action android:name="android.intent.action.VIEW"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <category android:name="android.intent.category.BROWSABLE"/>
            <data android:scheme="http"
                  android:host="*"
                  android:pathPattern=".*\\.ext" />
            <data android:scheme="https"
                  android:host="*"
                  android:pathPattern=".*\\.ext" />
            <data android:scheme="ftp"
                  android:host="*"
                  android:pathPattern=".*\\.ext" />

        </intent-filter>

คุณได้ทดสอบคำตอบนี้ด้วยไฟล์แนบของ Gmail หรือยัง
IgorGanapolsky

0

อ่าน https://developer.android.com/training/sharing/receive นี้จะช่วยในการเริ่มต้น จากนั้นในไฟล์รายการให้ลองใช้ตัวกรองความตั้งใจด้านล่างเมื่อลงทะเบียนผู้รับในกิจกรรมที่จะเปิด

<intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <data android:scheme="content"/>
            <category android:name="android.intent.category.BROWSABLE"/>
            <category android:name="android.intent.category.DEFAULT" />
            <data android:mimeType="application/your_extension" />
</intent-filter>

ตรวจสอบให้แน่ใจว่ามีการระบุส่วนขยายโดยไม่มี "." ในนั้น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.