You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter Android开发:限制分享文件时应用选择器仅显示指定应用

解决Flutter Share_plus仅显示WhatsApp/Telegram分享的问题

你添加的<queries>标签只是满足Android 11+的包可见性要求,让你的应用能检测到WhatsApp和Telegram的存在,但不会改变系统分享选择器的显示逻辑——系统默认会列出所有支持ACTION_SEND/ACTION_SEND_MULTIPLE的应用,所以无关应用还是会出现。

要实现只显示指定应用,或者过滤支持多文件分享的应用,需要自定义分享逻辑,以下是具体方案:


方案1:强制仅显示WhatsApp和Telegram

通过手动构建这两个应用的分享Intent,再生成只包含这些Intent的系统选择器。需要结合Flutter MethodChannel调用原生Android代码实现:

1. Flutter端代码

import 'package:flutter/services.dart';

class CustomShare {
  static const _channel = MethodChannel('custom_share');

  // 调用原生分享方法,传入文件路径列表
  static Future<void> shareFiles(List<String> filePaths) async {
    try {
      await _channel.invokeMethod('shareToSpecificApps', {'filePaths': filePaths});
    } on PlatformException catch (e) {
      print('分享失败:${e.message}');
    }
  }
}

2. Android端代码(MainActivity)

import android.content.Intent
import android.net.Uri
import android.os.Build
import androidx.core.content.FileProvider
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import java.io.File

class MainActivity : FlutterActivity() {
    private val CHANNEL = "custom_share"

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
            if (call.method == "shareToSpecificApps") {
                val filePaths = call.argument<List<String>>("filePaths") ?: emptyList()
                shareToTargetApps(filePaths)
                result.success(null)
            } else {
                result.notImplemented()
            }
        }
    }

    private fun shareToTargetApps(filePaths: List<String>) {
        // 转换文件路径为Uri(适配Android 7+的文件权限)
        val uris = mutableListOf<Uri>()
        filePaths.forEach { path ->
            val file = File(path)
            val uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                FileProvider.getUriForFile(this, "${packageName}.fileprovider", file)
            } else {
                Uri.fromFile(file)
            }
            uris.add(uri)
        }

        val targetIntents = mutableListOf<Intent>()

        // 添加WhatsApp分享Intent(先检查是否安装)
        packageManager.getLaunchIntentForPackage("com.whatsapp")?.let {
            val waIntent = Intent(Intent.ACTION_SEND_MULTIPLE).apply {
                type = "*/*" // 根据你的文件类型修改,比如"image/*"
                putParcelableArrayListExtra(Intent.EXTRA_STREAM, ArrayList(uris))
                setPackage("com.whatsapp")
                addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
            }
            targetIntents.add(waIntent)
        }

        // 添加Telegram分享Intent(先检查是否安装)
        packageManager.getLaunchIntentForPackage("org.telegram.messenger")?.let {
            val tgIntent = Intent(Intent.ACTION_SEND_MULTIPLE).apply {
                type = "*/*"
                putParcelableArrayListExtra(Intent.EXTRA_STREAM, ArrayList(uris))
                setPackage("org.telegram.messenger")
                addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
            }
            targetIntents.add(tgIntent)
        }

        if (targetIntents.isEmpty()) {
            // 没有安装目标应用,跳转到应用商店
            val storeIntent = Intent(Intent.ACTION_VIEW).apply {
                data = Uri.parse("market://search?q=WhatsApp+or+Telegram")
            }
            startActivity(storeIntent)
            return
        }

        // 生成仅包含目标应用的选择器
        val chooser = Intent.createChooser(targetIntents.removeAt(0), "选择分享应用")
        chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetIntents.toTypedArray())
        startActivity(chooser)
    }
}

3. 配置FileProvider(AndroidManifest.xml)

在<application>标签内添加:

<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="${applicationId}.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>

然后在res/xml目录下创建file_paths.xml文件:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-files-path name="app_files" path="." />
    <external-cache-path name="app_cache" path="." />
    <!-- 根据你的文件存储路径添加对应配置 -->
</paths>

方案2:仅显示支持多文件分享的应用

如果接受过滤出所有支持多文件分享的应用,可以修改原生代码,查询系统中所有支持ACTION_SEND_MULTIPLE的应用,再生成选择器:

// 查询所有支持多文件分享的应用包名
private fun getMultiFileShareApps(): List<String> {
    val intent = Intent(Intent.ACTION_SEND_MULTIPLE).apply {
        type = "*/*"
    }
    val resolveInfos = packageManager.queryIntentActivities(intent, 0)
    return resolveInfos.map { it.activityInfo.packageName }.distinct()
}

然后在构建targetIntents时,遍历上述包名列表,为每个包创建对应的分享Intent即可。


内容的提问来源于stack exchange,提问作者Slava709

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 02:55:29