首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> J2ME

J2ME 簡訊發送實作指南:WMA API 完整範例與三種發送模式比較

     編輯:J2ME

三種簡訊發送模式比較

模式架構優點缺點適用場景
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 略...
}

關鍵部署細節

  1. JAD 權限宣告 (MIDP 2.0 必須,否則拋 SecurityException):
    MIDlet-Permissions: javax.microedition.io.Connector.sms
    
    若需不彈窗詢問,需簽名並申請 MIDlet-Permissions-Opt。
  2. 號碼格式:國際格式 +,台灣範例 +886912345678。勿含空格、連字號。
  3. 分段簡訊:WMA 實作通常自動處理超長分段 (Concatenated SMS),但部份舊手機僅支援單段 160/70 字元,建議業務端自行截斷或分批。
  4. 模擬器測試: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 監聽傳入簡訊。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved