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

Flutter Dart中通过REST API发送拦截短信及后台监听故障求助

报错原因与修复方案

1. 现有报错修复

你遇到的invalid argument(s) (onerror): the error handler of future.catchError must return a value of the future's type报错,是两个问题共同导致的:

  • catchError传入的handleError是void返回类型,但interceptedMessage方法返回的是Future<SmsResponse>,catchError要求错误处理函数必须返回和原Future同类型的值,或直接抛出异常。
  • interceptedMessage方法存在多个分支返回值不符合要求:401、其他状态码分支返回的是入参param(dynamic类型),最后的catch块只打印错误没有返回值。

错误处理函数修改

// 修改handleError返回SmsResponse类型,适配catchError要求
SmsResponse handleError(error) {
  //hideLoading();
  if (error is BadRequestException) {
    var message = error.message;
    DialogHelper.showErroDialog(description: message);
  } else if (error is FetchDataException) {
    var message = error.message;
    DialogHelper.showErroDialog(description: message);
  } else if (error is ApiNotRespondingException) {
    DialogHelper.showErroDialog(
        description: 'Oops! It took longer to respond.');
  } else if (error is SocketException) {
    print(error);
  } else {
    print("All OK");
  }
  // 错误场景返回失败状态的SmsResponse,可根据你定义的SmsResponse结构调整
  return SmsResponse(status: "Failed", message: error.toString());
}

API接口类修改

Future<SmsResponse> interceptedMessage(dynamic param) async {
  var client = http.Client();
  String? token = await storage.readSecureToken('key');
  if (token == null) {
    return SmsResponse(status: "Failed", message: "No token stored in storage");
  }
  try {
    var response = await client
        .post(
          Uri.https("baseURL", "endpoint"),
          headers: <String, String>{
            'Authorization': 'Token $token',
            'Content-Type': 'application/json', // 新增请求头,适配json传参
          },
          body: jsonEncode(param), // 把参数转成json字符串,不能直接传Map
        )
        .timeout(Duration(seconds: TIME_CONST))
        .catchError(handleError);
    if (response.statusCode == 200) {
      print('Response Body: ${response.body}');
      final data = await jsonDecode(response.body);
      return SmsResponse.fromJson(data);
    } else if (response.statusCode == 401) {
      print("Unauthorized Request");
      return SmsResponse(status: "Failed", message: "Unauthorized");
    } else {
      print("Bad Input, status code: ${response.statusCode}");
      return SmsResponse(status: "Failed", message: "Request failed with code ${response.statusCode}");
    }
  } catch(e){
    print(e);
    return SmsResponse(status: "Failed", message: e.toString());
  } finally {
    client.close(); // 用完关闭client,避免内存泄漏
  }
}

2. 收到短信自动触发API调用

直接在onMessage回调里拿到短信内容后调用上传接口即可,同时可传入短信的真实发送方、接收时间等信息:

onMessage(
  SmsMessage message,
) async {
  setState(() {
    body = message.body ?? "Error reading message body.";
    print("$body");
  });
  // 新增:收到短信后自动调用上传接口
  final messaging = ApiService();
  messaging.interceptedMessage({
    "id": DateTime.now().millisecondsSinceEpoch, // 用时间戳作为唯一id
    "body": body,
    "senderName": message.address ?? "未知发送方", // 取真实发送方号码
    "timeStamp": DateTime.now().toIso8601String(), // 取真实接收时间
  }).then((value) {
    if (value.status == "Success") {
      print('Message Intercepted and uploaded');
    } else {
      print('Upload failed: ${value.message}');
    }
  });
}

3. 后台拦截功能实现

telephony插件的后台短信监听要求onBackgroundMessage是顶层函数(不能是类的成员方法),因为后台运行在独立的isolate里,无法访问主线程的类实例和状态,需要单独实现:

  1. 首先在全局位置定义后台消息处理函数:
// 全局顶层函数,处理后台收到的短信
@pragma('vm:entry-point') // 必须加这个注解,避免release打包时被混淆
void onBackgroundMessage(SmsMessage message) async {
  // 后台isolate需要重新初始化依赖,比如存储、ApiService
  await storage.init(); // 按你使用的存储组件初始化逻辑调整
  final messaging = ApiService();
  // 调用上传接口,逻辑和前台一致
  await messaging.interceptedMessage({
    "id": DateTime.now().millisecondsSinceEpoch,
    "body": message.body ?? "",
    "senderName": message.address ?? "未知发送方",
    "timeStamp": DateTime.now().toIso8601String(),
  });
}
  1. 安卓端需要在AndroidManifest.xml里添加必要权限:
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
  1. 建议在应用启动时就申请短信权限,不要等到页面初始化才申请,避免后台场景下权限失效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 06:12:03