三種簡訊發送模式比較
| 模式 | 架構 | 優點 | 缺點 | 適用場景 |
| 1. 網關發送 | App → HTTP → 運營商 SMPP 閘道 → 手機 | 無需手機支援特定 API;可發送海量簡訊 | 需購買閘道服務;有網路延遲;成本較高 | 企業級通知、行銷群發、驗證碼 |
| 2. PC 連線手機 (AT 指令) | PC App → 序列埠/藍牙 → 手機 Modem → 基地台 | 使用手機 SIM 卡發送,費率同一般簡訊 | 需實體連線;依賴廠商 AT 指令集差異大 | 個人小工具、測試用途 |
| 3. 手機端原生發送 (WMA) | MIDlet → WMA API → 手機基頻 → 基地台 | 無額外成本;離線可發;整合於應用流程 | 需手機支援 WMA (MIDP 2.0 內建 / MIDP 1.0 需廠商擴充) | 行動應用內建通訊、即時通訊、緊急求助 |
WMA (Wireless Messaging API) 核心類別
javax.wireless.messaging.MessageConnection:連線管理
javax.wireless.messaging.TextMessage:文字簡訊
javax.wireless.messaging.BinaryMessage:二進位簡訊 (含 UDH、WAP Push 等)
javax.microedition.io.Connector:統一開啟協定連線
核心發送工具類:SMSUtil
package com.example.util;
import javax.wireless.messaging.*;
import javax.microedition.io.*;
import java.io.IOException;
public class SMSUtil {
/**
* 發送文字簡訊
* @param content 簡訊內容 (建議 ≤ 160 英文字元 / 70 中文字元,超長會自動分段)
* @param phoneNumber 接收方號碼,格式:"+886912345678" (含國碼)
* @return 發送成功 true,失敗 false
*/
public static boolean send(String content, String phoneNumber) {
MessageConnection conn = null;
try {
// 協定格式:sms://+<國碼><號碼> ,亦可加 port: sms://+886912345678:5000
String address = "sms://+" + phoneNumber;
conn = (MessageConnection) Connector.open(address);
// 建立文字簡訊
TextMessage msg = (TextMessage) conn.newMessage(MessageConnection.TEXT_MESSAGE);
msg.setPayloadText(content);
// 發送 (同步阻塞直到送達 SMSC 或超時)
conn.send(msg);
return true;
} catch (Exception e) {
// 常見例外:SecurityException(未授權)、IOException(網路/模組錯誤)、IllegalArgumentException(號碼格式錯)
// 實際專案建議記錄 e.getMessage() 供診斷
return false;
} finally {
if (conn != null) {
try { conn.close(); } catch (IOException ignore) {}
}
}
}
/**
* 發送二進位簡訊 (進階:WAP Push、UDH、指定編碼等)
*/
public static boolean sendBinary(byte[] payload, String phoneNumber, String port) {
MessageConnection conn = null;
try {
String address = "sms://+" + phoneNumber + (port != null ? ":" + port : "");
conn = (MessageConnection) Connector.open(address);
BinaryMessage msg = (BinaryMessage) conn.newMessage(MessageConnection.BINARY_MESSAGE);
msg.setPayloadData(payload);
conn.send(msg);
return true;
} catch (Exception e) {
return false;
} finally {
if (conn != null) try { conn.close(); } catch (IOException ignore) {}
}
}
}
MIDlet 整合範例:簡訊發送介面
public class SMSSenderMIDlet extends MIDlet implements CommandListener {
private Display display;
private Form mainForm;
private TextField phoneField, contentField;
private Command sendCmd = new Command("發送", Command.OK, 1);
private Command exitCmd = new Command("離開", Command.EXIT, 2);
protected void startApp() {
display = Display.getDisplay(this);
mainForm = new Form("簡訊發送");
phoneField = new TextField("手機號碼:", "+886", 20, TextField.PHONENUMBER);
contentField = new TextField("內容:", "", 160, TextField.ANY);
mainForm.append(phoneField);
mainForm.append(contentField);
mainForm.addCommand(sendCmd);
mainForm.addCommand(exitCmd);
mainForm.setCommandListener(this);
display.setCurrent(mainForm);
}
public void commandAction(Command c, Displayable d) {
if (c == sendCmd) {
final String phone = phoneField.getString().trim();
final String content = contentField.getString();
if (phone.length() < 5 || content.length() == 0) {
showAlert("請填寫完整號碼與內容");
return;
}
// 背景執行緒發送,避免阻塞 UI
new Thread(() -> {
boolean ok = SMSUtil.send(content, phone.replace("+", ""));
display.callSerially(() -> showAlert(ok ? "發送成功!" : "發送失敗,請檢查號碼或 SIM 卡"));
}).start();
} else if (c == exitCmd) {
notifyDestroyed();
}
}
private void showAlert(String msg) {
Alert a = new Alert("結果", msg, null, AlertType.INFO);
a.setTimeout(2000);
display.setCurrent(a, mainForm);
}
// pauseApp, destroyApp 略...
}
關鍵部署細節
- JAD 權限宣告 (MIDP 2.0 必須,否則拋 SecurityException):
MIDlet-Permissions: javax.microedition.io.Connector.sms
若需不彈窗詢問,需簽名並申請 MIDlet-Permissions-Opt。
- 號碼格式:國際格式
+,台灣範例 +886912345678。勿含空格、連字號。
- 分段簡訊:WMA 實作通常自動處理超長分段 (Concatenated SMS),但部份舊手機僅支援單段 160/70 字元,建議業務端自行截斷或分批。
- 模擬器測試:WTK 2.5+ 內建 WMA 模擬器 (Tools → WMA Console) 可模擬收發,實機測試仍不可或缺。
常見錯誤與對策
| 例外/現象 | 可能原因 | 對策 |
| SecurityException | 未在 JAD 宣告權限 / 用戶拒絕授權 | 補上 MIDlet-Permissions;引導用戶選「允許」或簽名發布 |
| IOException: "Invalid address" | 號碼格式錯誤 / 缺少國碼 | 確認格式為 sms://+CCXXXXXXXXXX |
| 發送無反應、長時間卡住 | 手機訊號弱 / SMSC 設定錯誤 / SIM 卡異常 | 檢查訊號、簡訊中心號碼設定、換張 SIM 測試 |
| 中文顯示亂碼 | 編碼不一致 | WMA TextMessage 內部使用 UCS-2,Java String 為 UTF-16,通常自動轉換正確;若異常嘗試 BinaryMessage 指定編碼 |
小結
WMA API 讓 J2ME 應用擁有原生簡訊發送能力,零成本、高整合度。掌握 MessageConnection、TextMessage 核心流程,配合權限管理與錯誤處理,即可打造可靠的行動通訊功能。對於需要雙向通訊 (收發) 的場景,可進一步實作 MessageListener 監聽傳入簡訊。