iT邦幫忙

2025 iThome 鐵人賽

DAY 25
0
生成式 AI

三十天解鎖上下文超能力:MCP 實戰系列 第 25

Day 25 - 跨平台實戰 V:讓 iOS App 活起來!發送第一筆 API 請求

  • 分享至 

  • xImage
  •  

大家好,鐵人賽堂堂邁入第二十五日!

昨天,我們的 App 已經能夠成功地顯示靜態的對話內容。今天,是時候讓它「活」過來了!我們將把前端的 UI 操作,與我們在 Day 22 建立的 NetworkManager 完美結合,讓使用者在按下「發送」按鈕的那一刻,App 能夠真正地與我們後端的 Python AI Agent 進行溝通。

一、與後端的第一次握手:建立 Session

根據 adk api_server 的設計,在我們開始傳送聊天訊息之前,客戶端(也就是我們的 App)需要先呼叫一次 /sessions 端點,來建立一個對話的 Session ID。

我們在 MainViewController.swift 中建立一個 updateUserSession 函式來完成這個任務,並在 App 啟動時 (viewDidLoad) 就呼叫它。

// MainViewController.swift
override func viewDidLoad() {
    super.viewDidLoad()
    setupUI()
    // loadInitialMessages() // 我們不再需要假資料了
    
    // 在 App 啟動時,就與後端建立 Session
    Task {
        await updateUserSession()
    }
}

func updateUserSession() async {
    do {
        // 準備一個簡單的請求 Body
        let requestBody = UpdateSessionRequest(state: ["key1": "value1"])
        
        // 使用我們萬能的 NetworkManager 發送請求
        // 注意:我們不需要關心回傳的 response,因為 adk-api 會在後端處理好 Session
        let _: UpdateSessionResponse = try await NetworkManager.shared.requestData(
            method: .post,
            server: .adk,
            path: .session,
            parameters: requestBody
        )
        print(" 成功建立或更新 Session!")
        
    } catch {
        print(" 更新使用者 Session 失敗:\(error)")
        // 可以在此處彈出錯誤提示
    }
}

現在,當 App 一啟動,它就會自動在背景與我們的 Python 後端進行第一次的「握手」,為接下來的對話做好準備。

二、連接「發送」按鈕與網路請求

接下來是最核心的部分:當使用者輸入文字並按下「發送」按鈕時,觸發 runAgent 函式來呼叫 API。

首先,我們將發送按鈕的 TouchUpInside 事件,連接到 MainViewController.swift 中的 @IBAction func sendButtonTapped

// MainViewController.swift
@IBAction func sendButtonTapped(_ sender: UIButton) {
    // 1. 取得輸入框中的文字,並檢查是否為空
    guard let text = txfMessage.text, !text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else {
        return
    }
    
    // 2. 將使用者的訊息立即顯示在畫面上
    let userMessage = Message(text: text, sender: .user)
    messages.append(userMessage)
    txfMessage.text = ""
    tbvChat.reloadData()
    scrollToBottom(animated: true)
    
    // 3. 建立一個非同步任務,在背景執行我們的 API 呼叫
    Task {
        await runAgent(for: text)
    }
}

三、runAgent 的實現:組裝並發送請求

runAgent 函式是我們 App 的大腦,負責將使用者的文字,打包成符合 adk-api 規範的請求,並透過 NetworkManager 發送出去。

// MainViewController.swift
func runAgent(for text: String) async {
    do {
        // 1. 根據 API 規格,組裝出巢狀的 Request Body
        let messagePart = MessagePart(text: text)
        let messagePayload = MessagePayload(role: "user", parts: [messagePart])
        let requestBody = SendMessageRequest(
            appName: "multi_tool_agent",
            userId: "u_123",
            sessionId: "s_123",
            newMessage: messagePayload
        )
        
        // 2. 呼叫 NetworkManager 發送請求!
        // response 的型別會是我們在 Day 21 定義的 SendMessageResponse
        let response: SendMessageResponse = try await NetworkManager.shared.requestData(
            method: .post,
            server: .adk,
            path: .run,
            parameters: requestBody
        )
        
        // 暫時先在控制台印出回應,確認是否成功
        print("成功收到 Agent 回應: \(response)")
        
    } catch {
        print("呼叫 Agent 失敗: \(error)")
        // 可以在此處將錯誤訊息顯示在畫面上
    }
}

寫完後終於可以串接 api 囉!可以跟伺服器做連接了!但...還是會出現錯誤

截圖 2025-09-25 下午3.27.18

截圖 2025-09-25 15.14.47

失敗~~~連接不到 server

今日總結

雖然已經把請求丟出了,但都無法連接到server,不過沒關係!我們資工人就是不怕遇到bug!勇敢面對並解決bug!/images/emoticon/emoticon05.gif


上一篇
Day 24 - 跨平台實戰 IV:組裝聊天主畫面,讓 iOS app 對話動起來
下一篇
Day 26 - 跨平台實戰 VI:處理回應與動態更新 UI,完成互動閉環
系列文
三十天解鎖上下文超能力:MCP 實戰28
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言