Skip to content
索引

android 7.0邮件添加附件 exposed beyond app through ClipData.Item.getUri()

使用uniapp官方h5+ api,实现邮件功能,运行到真机后提示No Activity found to handle Intent,手机上安装邮箱应用后,该报错没有了,并且代码可以设置邮件内容,但是添加附件会出现上方报错

js
      var msg = plus.messaging.createMessage(plus.messaging.TYPE_EMAIL);
      msg.to = ["1.com"];
      msg.cc = ["2.com"];
      msg.subject = "测试邮件";
      msg.body = "This is Pandora example111111111 test message";
      var zipfile = plus.io.convertAbsoluteFileSystem(
        "/storage/emulated/0" + this.excelPath + ".zip"
      );
      msg.addAttachment(plus.io.convertLocalFileSystemURL(zipfile));
      plus.messaging.sendMessage(
        msg,
        function (res) {
          console.log("Send success!", res);
        },
        function (err) {
          console.log("Send failed!", err);
        }
      );
      var msg = plus.messaging.createMessage(plus.messaging.TYPE_EMAIL);
      msg.to = ["1.com"];
      msg.cc = ["2.com"];
      msg.subject = "测试邮件";
      msg.body = "This is Pandora example111111111 test message";
      var zipfile = plus.io.convertAbsoluteFileSystem(
        "/storage/emulated/0" + this.excelPath + ".zip"
      );
      msg.addAttachment(plus.io.convertLocalFileSystemURL(zipfile));
      plus.messaging.sendMessage(
        msg,
        function (res) {
          console.log("Send success!", res);
        },
        function (err) {
          console.log("Send failed!", err);
        }
      );

学习了原生安卓怎么实现该功能,试了试h5+ api参考原生安卓的写法,也能正常运行发送邮件,但是添加附件部分经过尝试也不行

js
        var Intent = plus.android.importClass("android.content.Intent");
        var mEmailIntent = new Intent();
        var Uri = plus.android.importClass("android.net.Uri");
        const uri = Uri.parse("mailto:");
        mEmailIntent.setData(uri);
        mEmailIntent.putExtra(Intent.EXTRA_EMAIL, ["347891134@qq.com"]);
        mEmailIntent.putExtra(Intent.EXTRA_CC, ["347891134@qq.com"]);
        mEmailIntent.putExtra(Intent.EXTRA_SUBJECT, "测试邮件");
        mEmailIntent.putExtra(
          Intent.EXTRA_TEXT,
          "This is Pandora example test message"
        );
        mEmailIntent.setAction(Intent.ACTION_SENDTO);
        var main = plus.android.runtimeMainActivity();
        main.startActivity(mEmailIntent);
        var Intent = plus.android.importClass("android.content.Intent");
        var mEmailIntent = new Intent();
        var Uri = plus.android.importClass("android.net.Uri");
        const uri = Uri.parse("mailto:");
        mEmailIntent.setData(uri);
        mEmailIntent.putExtra(Intent.EXTRA_EMAIL, ["347891134@qq.com"]);
        mEmailIntent.putExtra(Intent.EXTRA_CC, ["347891134@qq.com"]);
        mEmailIntent.putExtra(Intent.EXTRA_SUBJECT, "测试邮件");
        mEmailIntent.putExtra(
          Intent.EXTRA_TEXT,
          "This is Pandora example test message"
        );
        mEmailIntent.setAction(Intent.ACTION_SENDTO);
        var main = plus.android.runtimeMainActivity();
        main.startActivity(mEmailIntent);

最后通过阅读uniapp官方h5+ api源码地址

https://github.com/dcloudio/H5P.Android/blob/master/feature/messaging/src/io/dcloud/adapter/messaging/DHMessagCenter.java

结合网上资料,发现原因在于版本问题,Android7.0以上更改了文件url处理方式

参考大神代码,实现的分享插件https://ext.dcloud.net.cn/plugin?id=2307,其中是这样解决的https://github.com/lifejwang11/FileShare/blob/master/Android/sharefile/src/main/java/com/wgg/sharefile/Share.java

java
package com.wgg.sharefile;

import android.content.Context;
import android.net.Uri;
import android.os.Build;
import android.support.v4.content.FileProvider;

import java.io.File;

public class FileUtils {

    public static Uri getUri(Context context,String filePath){
        File tempFile = new File(filePath);
        //判断版本
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {   //如果在Android7.0以上,使用FileProvider获取Uri
            try{
                return FileProvider.getUriForFile(context, context.getPackageName() + ".provider", tempFile);
//                return FileProvider.getUriForFile(context, "uni.UNI899E01B.fileprovider", tempFile);
            }catch (Exception e){
                e.printStackTrace();
            }
        } else {    //否则使用Uri.fromFile(file)方法获取Uri
            return Uri.fromFile(tempFile);
        }
        return null;
    }

}
package com.wgg.sharefile;

import android.content.Context;
import android.net.Uri;
import android.os.Build;
import android.support.v4.content.FileProvider;

import java.io.File;

public class FileUtils {

    public static Uri getUri(Context context,String filePath){
        File tempFile = new File(filePath);
        //判断版本
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {   //如果在Android7.0以上,使用FileProvider获取Uri
            try{
                return FileProvider.getUriForFile(context, context.getPackageName() + ".provider", tempFile);
//                return FileProvider.getUriForFile(context, "uni.UNI899E01B.fileprovider", tempFile);
            }catch (Exception e){
                e.printStackTrace();
            }
        } else {    //否则使用Uri.fromFile(file)方法获取Uri
            return Uri.fromFile(tempFile);
        }
        return null;
    }

}

尝试降级安卓包版本

uniapp manifest中设置targetSdkVersion小于23,把安卓包降到低版本,这样安装包时会提示低版本,但是又会导致新问题

json
 /* 应用发布信息 */
    "distribute": {
      /* android打包配置 */
      "android": {
        "permissions": [
         
        ],
        "targetSdkVersion": 22
      },
 /* 应用发布信息 */
    "distribute": {
      /* android打包配置 */
      "android": {
        "permissions": [
         
        ],
        "targetSdkVersion": 22
      },

提示没有权限,参考大神代码,实现的分享插件https://ext.dcloud.net.cn/plugin?id=2307,其中原生安卓代码是这样解决的https://github.com/lifejwang11/FileShare/blob/master/Android/sharefile/src/main/java/com/wgg/sharefile/Share.java

java
  if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
            List<ResolveInfo> resInfoList = activity.getPackageManager().queryIntentActivities(shareIntent, PackageManager.MATCH_DEFAULT_ONLY);
            for (ResolveInfo resolveInfo : resInfoList) {
                String packageName = resolveInfo.activityInfo.packageName;
                activity.grantUriPermission(packageName, shareFileUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
            }
        }
  if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
            List<ResolveInfo> resInfoList = activity.getPackageManager().queryIntentActivities(shareIntent, PackageManager.MATCH_DEFAULT_ONLY);
            for (ResolveInfo resolveInfo : resInfoList) {
                String packageName = resolveInfo.activityInfo.packageName;
                activity.grantUriPermission(packageName, shareFileUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
            }
        }

所以最终还是要通过安卓原生代码来解决,开始学习安卓开发,打包安卓原生插件

Intent

在 Android 开发中,Intent 是一个重要的概念,它用于在不同的组件之间传递消息、执行操作或启动活动(Activity)。Intent 可以在应用内部组件之间进行通信,也可以与其他应用程序进行通信。

在这段代码中,Intent sendIntent = new Intent(Intent.ACTION_SEND); 创建了一个新的 Intent 实例,并指定了其动作为发送操作。这意味着这个 Intent 被用于启动一个发送的动作,通常是启动一个应用程序来发送数据(在这种情况下是多媒体消息)。

Intent 可以包含各种信息,比如操作的类型、数据的 URI、数据的 MIME 类型等。在这个例子中,通过 sendIntent.setType("*/*"); 设置了要发送的数据类型为任意类型,表示该 Intent 可以发送任意类型的数据。

一旦创建了 Intent 实例,并设置了必要的信息,就可以使用 startActivity() 方法来启动该 Intent,从而执行相应的操作。在这个例子中,_messaging.mWebview.getActivity().startActivity(sendIntent); 启动了发送 Intent,使得用户可以选择一个适合的应用程序来发送多媒体消息。

总的来说,Intent 是在 Android 中用于执行各种操作和通信的一种重要机制,它允许不同组件之间进行交互,并在 Android 应用程序中实现了丰富的功能。

ACTION_SEND

官方源码实现邮件发送 https://github.com/dcloudio/H5P.Android/blob/master/feature/messaging/src/io/dcloud/adapter/messaging/DHMessagCenter.java

java
  if( attachMentsSize > 1 ){
	mEmailIntent.setAction(Intent.ACTION_SEND_MULTIPLE);
	mEmailIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, pMessaging.mAttachments);
	mEmailIntent.setType("message/rfc822");
  }else if( attachMentsSize == 1 ){
	mEmailIntent.putExtra(Intent.EXTRA_STREAM, pMessaging.mAttachments.get(0));
	mEmailIntent.setType(PdrUtil.getMimeType(pMessaging.mAttachments.get(0).getPath()));
	mEmailIntent.setType("message/rfc882");
	mEmailIntent.setAction(Intent.ACTION_SEND);
  }else{
	mEmailIntent.setAction(Intent.ACTION_SENDTO);
  }
  if( attachMentsSize > 1 ){
	mEmailIntent.setAction(Intent.ACTION_SEND_MULTIPLE);
	mEmailIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, pMessaging.mAttachments);
	mEmailIntent.setType("message/rfc822");
  }else if( attachMentsSize == 1 ){
	mEmailIntent.putExtra(Intent.EXTRA_STREAM, pMessaging.mAttachments.get(0));
	mEmailIntent.setType(PdrUtil.getMimeType(pMessaging.mAttachments.get(0).getPath()));
	mEmailIntent.setType("message/rfc882");
	mEmailIntent.setAction(Intent.ACTION_SEND);
  }else{
	mEmailIntent.setAction(Intent.ACTION_SENDTO);
  }

ACTION_SENDTO 动作通常用于发送纯文本邮件。

ACTION_SEND 动作可以启动一个发送邮件的操作。

ACTION_SEND_MULTIPLE 动作则用于发送多个附件的邮件。

使用 ACTION_SEND 动作的 Intent,可以通过 EXTRA_STREAM 属性来附加一个附件。这样,邮件客户端就可以从 Intent 中获取附件并将其添加到邮件中,然后发送邮件。

mEmailIntent.setType("message/rfc822")邮件的 MIME 类型设置为 message/rfc822,这是邮件的标准类型,表示邮件内容遵循 RFC 822 标准。这个设置表明邮件内容是符合邮件格式规范的文本内容。

uts示例

也是一种实现原生插件的写法,https://ext.dcloud.net.cn/plugin?id=9295,但是研究后发现太复杂了,放弃放弃

ts
import Context from "android.content.Context";
import BatteryManager from "android.os.BatteryManager";

import {
  GetBatteryInfo,
  GetBatteryInfoOptions,
  GetBatteryInfoSuccess,
  GetBatteryInfoResult,
  GetBatteryInfoSync,
} from "../interface.uts";
import IntentFilter from "android.content.IntentFilter";
import Intent from "android.content.Intent";

/**
 * 异步获取电量
 */
export const getBatteryInfo: GetBatteryInfo = function (
  options: GetBatteryInfoOptions
) {
  const context = UTSAndroid.getAppContext();
  if (context != null) {
    const manager = context.getSystemService(
      Context.BATTERY_SERVICE
    ) as BatteryManager;
    const level = manager.getIntProperty(
      BatteryManager.BATTERY_PROPERTY_CAPACITY
    );

    let ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
    let batteryStatus = context.registerReceiver(null, ifilter);
    let status = batteryStatus?.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
    let isCharging =
      status == BatteryManager.BATTERY_STATUS_CHARGING ||
      status == BatteryManager.BATTERY_STATUS_FULL;

    const res: GetBatteryInfoSuccess = {
      errMsg: "getBatteryInfo:ok",
      level,
      isCharging: isCharging,
    };
    options.success?.(res);
    options.complete?.(res);
  } else {
    const res = new UniError(
      "uni-getBatteryInfo",
      1001,
      "getBatteryInfo:fail getAppContext is null"
    );
    options.fail?.(res);
    options.complete?.(res);
  }
};

/**
 * 同步获取电量示例
 */
export const getBatteryInfoSync: GetBatteryInfoSync =
  function (): GetBatteryInfoResult {
    const context = UTSAndroid.getAppContext();
    if (context != null) {
      const manager = context.getSystemService(
        Context.BATTERY_SERVICE
      ) as BatteryManager;
      const level = manager.getIntProperty(
        BatteryManager.BATTERY_PROPERTY_CAPACITY
      );

      let ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
      let batteryStatus = context.registerReceiver(null, ifilter);
      let status = batteryStatus?.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
      let isCharging =
        status == BatteryManager.BATTERY_STATUS_CHARGING ||
        status == BatteryManager.BATTERY_STATUS_FULL;

      const res: GetBatteryInfoResult = {
        level: level,
        isCharging: isCharging,
      };

      return res;
    } else {
      /**
       * 无有效上下文
       */
      const res: GetBatteryInfoResult = {
        level: -1,
        isCharging: false,
      };
      return res;
    }
  };

import Context from "android.content.Context";
import BatteryManager from "android.os.BatteryManager";

import {
  GetBatteryInfo,
  GetBatteryInfoOptions,
  GetBatteryInfoSuccess,
  GetBatteryInfoResult,
  GetBatteryInfoSync,
} from "../interface.uts";
import IntentFilter from "android.content.IntentFilter";
import Intent from "android.content.Intent";

/**
 * 异步获取电量
 */
export const getBatteryInfo: GetBatteryInfo = function (
  options: GetBatteryInfoOptions
) {
  const context = UTSAndroid.getAppContext();
  if (context != null) {
    const manager = context.getSystemService(
      Context.BATTERY_SERVICE
    ) as BatteryManager;
    const level = manager.getIntProperty(
      BatteryManager.BATTERY_PROPERTY_CAPACITY
    );

    let ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
    let batteryStatus = context.registerReceiver(null, ifilter);
    let status = batteryStatus?.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
    let isCharging =
      status == BatteryManager.BATTERY_STATUS_CHARGING ||
      status == BatteryManager.BATTERY_STATUS_FULL;

    const res: GetBatteryInfoSuccess = {
      errMsg: "getBatteryInfo:ok",
      level,
      isCharging: isCharging,
    };
    options.success?.(res);
    options.complete?.(res);
  } else {
    const res = new UniError(
      "uni-getBatteryInfo",
      1001,
      "getBatteryInfo:fail getAppContext is null"
    );
    options.fail?.(res);
    options.complete?.(res);
  }
};

/**
 * 同步获取电量示例
 */
export const getBatteryInfoSync: GetBatteryInfoSync =
  function (): GetBatteryInfoResult {
    const context = UTSAndroid.getAppContext();
    if (context != null) {
      const manager = context.getSystemService(
        Context.BATTERY_SERVICE
      ) as BatteryManager;
      const level = manager.getIntProperty(
        BatteryManager.BATTERY_PROPERTY_CAPACITY
      );

      let ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
      let batteryStatus = context.registerReceiver(null, ifilter);
      let status = batteryStatus?.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
      let isCharging =
        status == BatteryManager.BATTERY_STATUS_CHARGING ||
        status == BatteryManager.BATTERY_STATUS_FULL;

      const res: GetBatteryInfoResult = {
        level: level,
        isCharging: isCharging,
      };

      return res;
    } else {
      /**
       * 无有效上下文
       */
      const res: GetBatteryInfoResult = {
        level: -1,
        isCharging: false,
      };
      return res;
    }
  };

学习如何打包原生插件

https://juejin.cn/post/7194743378830409783

https://juejin.cn/post/7195018409543729189/

理解Android Studio中的Gradle

https://zhuanlan.zhihu.com/p/139685763

Android Studio的gradle sync是什么?

https://www.zhihu.com/question/369909080

和Maven一样是项目管理工具,可以对代码进行构建、依赖管理。

不用Maven、Gradle这些类似工具你只能手动加载包到你的Libs下,麻烦且容易出问题。

现在Web开发一般都会采用Maven,而Android开发由于Google推出的AS是指定的Gradle自然也就采用了它。

Gradle sync就是开始执行Gradle脚本,一般会将声明中的包库进行下载,由于不可描述的原因在国内的确存在fail的情况,作为程序员请先学会科学的上网方式。

安装Gradle

下载慢解决方案:使用浏览器下载到本地,然后配置Android Studio使用本地路径的Gradle:

1.https://gradle.org/releases/直接官方下载binary-only版本,格式是这样的:gradle-7.2-bin,这种包就是所需的。

2.修改Android Studio使用本地路径的Gradle,然后重新同步(同步指的就是点击右上角的小象图标,就会触发gradle),具体操作:解压gradle压缩包,file>setttings>gradle中使用本地路径解压后的gradle,默认置Android Studio使用的高版本java,可以安装7.2,7.2以上的版本没有尝试,参考文章:https://blog.csdn.net/C_biubiubiu/article/details/109863975。

没有assembleRelease

file -> setting -> Experimental -> 勾上 Configure all Gradle tasks during Gradle Sync (this can make Gradle Sync slower)选项,然后再选择file -> Sync Project......就有了

assembleRelease报错

https://stackoverflow.com/questions/67782975/how-to-fix-the-module-java-base-does-not-opens-java-io-to-unnamed-module

sh
org.gradle.jvmargs=-Xmx1536M \
--add-exports=java.base/sun.nio.ch=ALL-UNNAMED \
--add-opens=java.base/java.lang=ALL-UNNAMED \
--add-opens=java.base/java.lang.reflect=ALL-UNNAMED \
--add-opens=java.base/java.io=ALL-UNNAMED \
--add-exports=jdk.unsupported/sun.misc=ALL-UNNAMED
org.gradle.jvmargs=-Xmx1536M \
--add-exports=java.base/sun.nio.ch=ALL-UNNAMED \
--add-opens=java.base/java.lang=ALL-UNNAMED \
--add-opens=java.base/java.lang.reflect=ALL-UNNAMED \
--add-opens=java.base/java.io=ALL-UNNAMED \
--add-exports=jdk.unsupported/sun.misc=ALL-UNNAMED

需要更改build.gradle为对应的sdk版本

json
compileSdkVersion 30
compileSdkVersion 30

我的安卓插件

java
package com.example.mylibrary;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import io.dcloud.feature.uniapp.annotation.UniJSMethod;
import io.dcloud.feature.uniapp.bridge.UniJSCallback;
import io.dcloud.feature.uniapp.common.UniModule;

import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Build;
import androidx.core.content.FileProvider;
import java.io.File;
import java.util.List;

// 一定要继承UniModule
public class testModule extends UniModule {
    // 使用UniJSMethod注解,才能使用js调用
    @UniJSMethod(uiThread = true)
    public void  email (JSONObject options, UniJSCallback callback) {
        try{
        if (mUniSDKInstance.getContext() instanceof Activity) {
            Activity context = (Activity) mUniSDKInstance.getContext();
            String filePath = options.getString("filePath");

            Uri streamPath = FileProvider.getUriForFile(context, context.getPackageName() + ".provider", new File(filePath));
            Intent mEmailIntent = new Intent();
            Uri uri = Uri.parse("mailto:");
            JSONArray to = options.getJSONArray( "to");
            //创建一个与JSONArray 长度相同的String数组
            String[] strings_to = new String[to.size()];
            //使用JSONArray 中的toArray进行转换
            String[] strings_arr_to = to.toArray(strings_to);
            mEmailIntent.putExtra(Intent.EXTRA_EMAIL,  strings_arr_to);

            JSONArray cc = options.getJSONArray( "cc");
            String[] strings_cc = new String[cc.size()];
            String[] strings_arr_cc = cc.toArray(strings_cc);
            mEmailIntent.putExtra(Intent.EXTRA_CC, strings_arr_cc);

            mEmailIntent.putExtra(Intent.EXTRA_SUBJECT, options.getString("subject"));
            mEmailIntent.putExtra(
                    Intent.EXTRA_TEXT,
                    options.getString("body")
            );
            mEmailIntent.putExtra(Intent.EXTRA_STREAM, streamPath);
            mEmailIntent.setAction(Intent.ACTION_SEND);
            mEmailIntent.setData(uri);
            mEmailIntent.setType("*/*");
            if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
                List<ResolveInfo> resInfoList = context.getPackageManager().queryIntentActivities(mEmailIntent, PackageManager.MATCH_DEFAULT_ONLY);
                for (ResolveInfo resolveInfo : resInfoList) {
                    String packageName = resolveInfo.activityInfo.packageName;
                    context.grantUriPermission(packageName, streamPath, Intent.FLAG_GRANT_READ_URI_PERMISSION);
                }
            }
            context.startActivity(Intent.createChooser(mEmailIntent, "邮件"));
            callback.invoke(new JSONObject() {{
                put("code", 200);
                put("result", "成功");
            }});
        }

        }catch (Exception e){
            e.printStackTrace();
            callback.invoke(new JSONObject() {{
                put("code", -1);
                put("result", e.getMessage());
            }});
        }
    }
}
package com.example.mylibrary;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import io.dcloud.feature.uniapp.annotation.UniJSMethod;
import io.dcloud.feature.uniapp.bridge.UniJSCallback;
import io.dcloud.feature.uniapp.common.UniModule;

import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Build;
import androidx.core.content.FileProvider;
import java.io.File;
import java.util.List;

// 一定要继承UniModule
public class testModule extends UniModule {
    // 使用UniJSMethod注解,才能使用js调用
    @UniJSMethod(uiThread = true)
    public void  email (JSONObject options, UniJSCallback callback) {
        try{
        if (mUniSDKInstance.getContext() instanceof Activity) {
            Activity context = (Activity) mUniSDKInstance.getContext();
            String filePath = options.getString("filePath");

            Uri streamPath = FileProvider.getUriForFile(context, context.getPackageName() + ".provider", new File(filePath));
            Intent mEmailIntent = new Intent();
            Uri uri = Uri.parse("mailto:");
            JSONArray to = options.getJSONArray( "to");
            //创建一个与JSONArray 长度相同的String数组
            String[] strings_to = new String[to.size()];
            //使用JSONArray 中的toArray进行转换
            String[] strings_arr_to = to.toArray(strings_to);
            mEmailIntent.putExtra(Intent.EXTRA_EMAIL,  strings_arr_to);

            JSONArray cc = options.getJSONArray( "cc");
            String[] strings_cc = new String[cc.size()];
            String[] strings_arr_cc = cc.toArray(strings_cc);
            mEmailIntent.putExtra(Intent.EXTRA_CC, strings_arr_cc);

            mEmailIntent.putExtra(Intent.EXTRA_SUBJECT, options.getString("subject"));
            mEmailIntent.putExtra(
                    Intent.EXTRA_TEXT,
                    options.getString("body")
            );
            mEmailIntent.putExtra(Intent.EXTRA_STREAM, streamPath);
            mEmailIntent.setAction(Intent.ACTION_SEND);
            mEmailIntent.setData(uri);
            mEmailIntent.setType("*/*");
            if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
                List<ResolveInfo> resInfoList = context.getPackageManager().queryIntentActivities(mEmailIntent, PackageManager.MATCH_DEFAULT_ONLY);
                for (ResolveInfo resolveInfo : resInfoList) {
                    String packageName = resolveInfo.activityInfo.packageName;
                    context.grantUriPermission(packageName, streamPath, Intent.FLAG_GRANT_READ_URI_PERMISSION);
                }
            }
            context.startActivity(Intent.createChooser(mEmailIntent, "邮件"));
            callback.invoke(new JSONObject() {{
                put("code", 200);
                put("result", "成功");
            }});
        }

        }catch (Exception e){
            e.printStackTrace();
            callback.invoke(new JSONObject() {{
                put("code", -1);
                put("result", e.getMessage());
            }});
        }
    }
}

FileProvider 路径配置策略的理解

https://blog.csdn.net/u013553529/article/details/83900704

https://juejin.cn/post/6844903476892270605

选择文件

h5+ api获取图片路径

js
 // 从相册中选择图片
      console.log("从相册中选择多张图片:");
      plus.gallery.pick(
        function (e) {
          for (var i in e.files) {
            console.log(e.files[i]);
          }
        },
        function (e) {
          console.log("取消选择图片");
        },
        { filter: "image", multiple: true }
      );
 // 从相册中选择图片
      console.log("从相册中选择多张图片:");
      plus.gallery.pick(
        function (e) {
          for (var i in e.files) {
            console.log(e.files[i]);
          }
        },
        function (e) {
          console.log("取消选择图片");
        },
        { filter: "image", multiple: true }
      );

Released under the MIT License.