Android調(diào)用其他應(yīng)用打開各種附件(.doc/.pdf/.xls)

Android調(diào)用其他應(yīng)用打開各種附件(.doc/.pdf/.xls)

最近重構(gòu)掌上重郵的寫下載文件附件時(shí)遇到了一個(gè)問題:

附件下載完成后需要打開文件啊,不同文件打開怎么處理才優(yōu)雅呢?

成功操作后踩坑記錄整理于此

更新

Android N 版本適配

避雷

本文例子均為Kotlin編寫

思路

首先打開文件這種跳轉(zhuǎn)肯定是發(fā)intent出去,然后就是怎么傳遞文件信息和要打開的文件類型了

這里我發(fā)現(xiàn)了intent.setDataAndType(uri, type)

正文

那么整體的寫法就應(yīng)該是:

注意,這段代碼有倆坑惑畴,后文說明

if (file.exists()) {
    try {
        startActivity(Intent(Intent.ACTION_VIEW)
                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                .setDataAndType(Uri.fromFile(file), FileTypeHelper.getMIMEType(file)))
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

這里關(guān)鍵的就是獲取type的方法台妆,我單獨(dú)寫了一個(gè)Helper來處理蛋褥,因?yàn)閠ype畢竟很多彼宠,而且需要多次判斷。

import java.io.File

/**
 * Author: Hosigus
 * Date: 2018/9/27 17:56
 * Description: 打開對應(yīng)文件需要的type
 */
object FileTypeHelper {
    private val MIME_TABLE = mapOf(".doc" to "application/msword",
            ".docx" to "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
            ".xls" to "application/vnd.ms-excel",
            ".xlsx" to "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
            ".pdf" to "application/pdf",
            ".pps" to "application/vnd.ms-powerpoint",
            ".ppt" to "application/vnd.ms-powerpoint",
            ".pptx" to "application/vnd.openxmlformats-officedocument.presentationml.presentation",
            ".z" to "application/x-compress",
            ".zip" to "application/x-zip-compressed")

    /**
     * 獲取文件類型
     */
    fun getMIMEType(file: File): String {
        var type = "*/*"
        val fName = file.name

        val dotIndex = fName.lastIndexOf(".")
        if (dotIndex < 0) {
            return type
        }

        val end = fName.substring(dotIndex, fName.length).toLowerCase()
        if (end.isBlank()) return type

        type = MIME_TABLE[end] ?: return type
        return type
    }
}

有一堆映射诗力,查找起來就特別快特別方便了凰浮,再加上一些小判斷,保證傳出去的type不會(huì)有問題苇本,畢竟要保證打開文件出錯(cuò)不是在我的應(yīng)用內(nèi)嘛 (笑

看起來一切都很完美了袜茧,那么實(shí)際跑起來又如何?

android.os.FileUriExposedException

運(yùn)行在Android 7.0的系統(tǒng)上時(shí)瓣窄,會(huì)發(fā)現(xiàn)這個(gè)報(bào)錯(cuò)笛厦,Google 官方解釋:

對于面向 Android 7.0 的應(yīng)用,Android 框架執(zhí)行的 StrictMode API 政策禁止在應(yīng)用外部公開 file:// URI俺夕,即當(dāng)把targetSdkVersion指定成24及之上并且在API>=24的設(shè)備上運(yùn)行時(shí)裳凸,如果一項(xiàng)包含文件 URI 的 intent 離開應(yīng)用(如分享),則應(yīng)用出現(xiàn)故障劝贸,并出現(xiàn) FileUriExposedException 異常姨谷。

也就是說,Uri.fromFile(file) 這個(gè)方法在高版本不適用映九,正確的解決方案是通過FileProvider 來進(jìn)行操作梦湘,更具體的可以看下這篇博客.

總之,編寫了ContentProvider相關(guān)配置后件甥,原代碼如下:

if (file.exists()) {
    try {
        startActivity(Intent(Intent.ACTION_VIEW)
                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                .setDataAndType(file.uri, FileTypeHelper.getMIMEType(file)))
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

val File.uri: Uri
    get() = if (Build.VERSION.SDK_INT >= 24) {
        FileProvider.getUriForFile(context, authority, this)
    } else {
        Uri.fromFile(this)
    }

運(yùn)行之后發(fā)現(xiàn)成功跳轉(zhuǎn)捌议,但是!跳轉(zhuǎn)目標(biāo)應(yīng)用卻無法打開文件引有,查看后發(fā)現(xiàn)的確不是文件損壞瓣颅,用文件管理器是能打開的。那么原因肯定在于代碼錯(cuò)誤譬正。

分析發(fā)現(xiàn)宫补,不僅僅在Provider提供公開文件僻孝,還需要在Flag里提供可讀權(quán)限,最終代碼如下:

if (file.exists()) {
    try {
        startActivity(Intent(Intent.ACTION_VIEW)
                .addFlags(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION
                } else {
                    Intent.FLAG_ACTIVITY_NEW_TASK
                })
                .setDataAndType(file.uri, FileTypeHelper.getMIMEType(file)))
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

val File.uri: Uri
    get() = if (Build.VERSION.SDK_INT >= 24) {
        FileProvider.getUriForFile(context, authority, this)
    } else {
        Uri.fromFile(this)
    }

至此守谓,本篇博客結(jié)束,所以這個(gè)Android版本適配問題您单,還是蠻考驗(yàn)人經(jīng)歷的斋荞。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市虐秦,隨后出現(xiàn)的幾起案子平酿,更是在濱河造成了極大的恐慌,老刑警劉巖悦陋,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蜈彼,死亡現(xiàn)場離奇詭異,居然都是意外死亡俺驶,警方通過查閱死者的電腦和手機(jī)幸逆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來暮现,“玉大人还绘,你說我怎么就攤上這事∑艽” “怎么了拍顷?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長塘幅。 經(jīng)常有香客問我昔案,道長,這世上最難降的妖魔是什么电媳? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任踏揣,我火速辦了婚禮,結(jié)果婚禮上匆背,老公的妹妹穿的比我還像新娘呼伸。我一直安慰自己,他們只是感情好钝尸,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布括享。 她就那樣靜靜地躺著,像睡著了一般珍促。 火紅的嫁衣襯著肌膚如雪铃辖。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天猪叙,我揣著相機(jī)與錄音娇斩,去河邊找鬼仁卷。 笑死,一個(gè)胖子當(dāng)著我的面吹牛犬第,可吹牛的內(nèi)容都是我干的锦积。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼歉嗓,長吁一口氣:“原來是場噩夢啊……” “哼丰介!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起鉴分,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤哮幢,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后志珍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體橙垢,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年伦糯,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了柜某。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,785評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡敛纲,死狀恐怖莺琳,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情载慈,我是刑警寧澤惭等,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站办铡,受9級特大地震影響辞做,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜寡具,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一秤茅、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧童叠,春花似錦框喳、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至杜秸,卻和暖如春放仗,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背撬碟。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工诞挨, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留莉撇,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓惶傻,卻偏偏與公主長得像棍郎,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子银室,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容