慣性聚合 高效追蹤和閱讀你感興趣的部落格、新聞、科技資訊
閱讀原文 在慣性聚合中打開

推薦訂閱源

博客园 - 司徒正美
V
V2EX
T
Tailwind CSS Blog
有赞技术团队
有赞技术团队
aimingoo的专栏
aimingoo的专栏
Apple Machine Learning Research
Apple Machine Learning Research
IT之家
IT之家
Blog — PlanetScale
Blog — PlanetScale
A
About on SuperTechFans
月光博客
月光博客
T
The Blog of Author Tim Ferriss
宝玉的分享
宝玉的分享
Martin Fowler
Martin Fowler
博客园 - 聂微东
The GitHub Blog
The GitHub Blog
V
Visual Studio Blog
WordPress大学
WordPress大学
酷 壳 – CoolShell
酷 壳 – CoolShell
Engineering at Meta
Engineering at Meta
GbyAI
GbyAI

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python)
來自Google I/O 2026的睡眠者公告,將改變我們對應用程式的想法
Vrushali · 2026-05-24 · via DEV Community

這是一份提交給Google I/O寫作挑戰


每個人都離開Google I/O 2026後都在談論Compose First、Gemini整合以及Android 17的自適應佈局推動。公道——這些確實很重要。但最讓我無法停止思考的宣布卻幾乎沒有得到頭條新聞:那就是AppFunctions API

我已經開發安卓應用程式十年了。我見過 API 的來來去去。這個感覺不一樣 — 不僅僅是因為它今天做了什麼,而是因為它所傳達的關於應用程式正在變成的訊號。


AppFunctions 其實是什麼

在核心上,AppFunctions 讓你的應用程式可以直接向 AI 助手暴露獨立、命名的動作。想想:

  • "Create expense report"
  • "Book appointment"
  • "Send daily update"

不是由使用者啟動您的應用程式,導航至螢幕,點擊流程 — 類似於 Gemini 的代理程式可以直接代為執行這些動作,而應用程式從未來到前景.

這是一個大致的概念,關於如何註冊 AppFunction 的.

@AppFunction
suspend fun createExpenseReport(
    context: AppFunctionContext,
    params: CreateExpenseParams
): ExpenseResult {
    // your business logic here
    return ExpenseResult(id = repo.create(params))
}

進入全螢幕模式 離開全螢幕模式

你定義函數。你定義參數。AI 決定何時以及如何呼叫它.


如何整合 AppFunctions:一個逐步範例

讓我們讓這個具體化。這裡是從零到可呼叫 Gemini 的完整整合.

步驟 1 — 添加相依性

// build.gradle.kts (module)
dependencies {
    implementation("androidx.appfunctions:appfunctions:1.0.0-alpha01")
    ksp("androidx.appfunctions:appfunctions-compiler:1.0.0-alpha01")
}

進入全螢幕模式 退出全螢幕模式

第 2 步 — 定義您的輸入/輸出類型

AppFunctions 使用類型化的 Kotlin 資料類別。保持它們可序列化 — AI 代理需要從自然語言中構建它們.

@Serializable
data class CreateExpenseParams(
    val title: String,
    val amount: Double,
    val category: String? = null  // nullable — agent may not always provide this
)

@Serializable
data class ExpenseResult(
    val id: String,
    val success: Boolean,
    val message: String
)

進入全螢幕模式 退出全螢幕模式

第 3 步 — 標註您的函數

使用@AppFunction 在一個暫停函數上。註解處理器在編譯時生成註冊模式 — 無需模板化的 XML。

class ExpenseAppFunctions(
    private val repo: ExpenseRepository
) {

    @AppFunction
    suspend fun createExpenseReport(
        context: AppFunctionContext,
        params: CreateExpenseParams
    ): ExpenseResult {
        val id = repo.create(params)
        return ExpenseResult(
            id = id,
            success = true,
            message = "Expense created: ${params.title}"
        )
    }
}

進入全螢幕模式 退出全螢幕模式

第 4 步 — 讓它對代理安全 (每個人都跳過的步驟)

代理可以在網絡失敗時重試。沒有幂等性,一個用戶的語音指令可能會創建重複的記錄。

@AppFunction
suspend fun createExpenseReport(
    context: AppFunctionContext,
    params: CreateExpenseParams
): ExpenseResult {

    // Idempotency: return existing record if already created
    val existing = repo.findByTitle(params.title)
    if (existing != null) {
        return ExpenseResult(
            id = existing.id,
            success = true,
            message = "Already exists"
        )
    }
    return ExpenseResult(id = repo.create(params), success = true, message = "Created")
}

進入全螢幕模式 離開全螢幕模式

注意: 若要進行更精細的控制,請使用AppFunctionContext.callerPackageName來為每個代理設定 idempotency keys.

第 5 步 — 在 AndroidManifest 中註冊

若沒有這一步,Gemini 就無法在執行時發現您的函數.

<!-- AndroidManifest.xml -->
<service
    android:name=".ExpenseAppFunctions"
    android:exported="true"
    android:permission="android.permission.BIND_APP_FUNCTION_SERVICE">

    <intent-filter>
        <action android:name="androidx.appfunctions.AppFunctionService"/>
    </intent-filter>

</service>

進入全螢幕模式 離開全螢幕模式

第 6 步 — Gemini 如何處理它

註冊後,當使用者輸入 "將 45 英鎊的計程車費用列為支出" 時,這項功能便在背景執行 — 不需介面、不需導航、不需點擊:

// Gemini constructs and executes this on-device
val result = appFunctionManager.executeAppFunction(
    targetPackage = "com.yourapp",
    functionId = "createExpenseReport",
    params = CreateExpenseParams(
        title = "Taxi",
        amount = 45.0,
        category = "Transport"
    )
)
// result.message → "Expense created: Taxi"

進入全螢幕模式 離開全螢幕模式

那是完整的流程。從依賴到可由代理調用的行動有六個步驟——而實際上的大部分工作是在步驟 3 和 4,不是在 1 和


為何這比聽起來更重大

讓我直接說明這需要的思維轉變.

在過去十年中,Android 應用程式一直是 被動工具。用戶打開它們,與它們互動,關閉它們。應用程式等待。用戶回來了。這就是模式.

AppFunctions徹底打破這個模式.

注意: 你的應用程式不再僅僅是介面。它是一組可以被外部智能調用的功能——一個為用戶代為操作,跨越多個應用程式,而無需明確導航的智能。

這不是一個增量更新。這是一種不同的典範.

想想這對於我們永遠以來所持有的用戶體驗假設意味著什麼:

  • 設計用來引導用戶的啟用流程?如果代理跳過它們,那麼相對來說就不那麼重要了.
  • 導航架構?它仍然重要,但它不再是最終的唯一入口。
  • 狀態管理?現在需要考慮在您的UI生命週期之外觸發的動作.

誰都不談的部分:這對開發者提出了什麼要求

我認為大多數報導都在這裡失分了.

所有人都將AppFunctions框架為一個要"添加"到您應用程式中的功能。加一些註解,暴露幾個動作,完畢。但這種框架忽略了架構上的影響。

您的應用程式邏輯必須符合代理程式的要求.

這表示:

  • 單次執行的效果更為重要.如果發生網路暫時中斷,代理程式可能會呼叫createExpenseReport兩次。您有處理這種情況嗎?
  • 錯誤訊息必須能被機器讀取.如果您的函式失敗,代理程式需要結構化的資訊來恢復或回報——不是簡單的提示訊息。
  • 權限與認證需要明確. 代表使用者行動的代理仍然需要尊重範圍。你不能僅僅假設環境中的使用者認證.

這相對於「增加一個功能」更像是「重新思考你的服務層。」


我的誠實看法:令人興奮,但我們尚未準備好

我想要誠實地說——廣泛來說,Android開發者社群並未準備好這次轉變。

我們仍在遷移至 Compose。許多團隊仍在解開 MVVM 的麻煩。而我們現在卻被要求思考我們的應用程式作為代理相容的 API?

注意: 「Google 宣布 AppFunctions」與「大多數生產應用程式提供良好設計的 AppFunctions」之間的差距將以年計,而非月計。而這是可以接受的 — 但前提是我們開始思考架構目前.

將會走在這條曲線前面開發者,是那些現在就開始將他們的業務邏輯視為一個一等API的人 — 清潔的使用案例、清晰的輸入/輸出合約、正確的錯誤處理。不是因為還沒有代理調用它,而是因為良好的架構會為未來帶來回報.


我明天要告訴我的團隊

如果我明天去 standup 時,從 I/O 2026 帶走的一點收穫是這樣的:

開始審計你的應用場景,確保它們能夠應對 AI 前景。

不是為了在下一個 sprint 發布 AppFunctions — 而是問:如果一個 AI 需要無人鍵盤的情況下觸發這個動作,我們的程式碼能夠應付得了嗎?錯誤狀態會合理嗎?認證模型會有效嗎?

僅僅是這個問題就會浮現出許多值得處理的架構債務,無論是AppFunctions。


論隱私 — 因為總有人要說出來

我對AppFunctions充滿興奮。但如果我不指出這個問題開啟的隱私表面,我就對你做了不公。

當代理程式無需使用者明確點擊即可啟動您的應用程式時,同意模式就變得模糊不清。有幾件事值得深入思考:

  • 代理人默默地行動。用戶曾經說過「添加計程車費用」一次 — 他們沒有檢查哪些數據離開了他們的設備或哪些系統被觸及。你的功能只需要做它說的確切的事情。
  • 敏感資料需要明確的範圍界定。 若您的AppFunction觸及財務、健康或訊息,請將輸出視為公開API回應。回傳所需的最少數據,不多不少。
  • 驗證callerPackageName。 AppFunctionContext可提供呼叫代理的套件。對於敏感操作,請白名單信任的呼叫者 — 不要假設所有代理都應得到同等信任。
  • 記錄每一次呼叫。 使用者應該能夠看到他們的代理為他們做了什麼。從第一天開始就建立那條審計軌跡.

好消息是:Android的BIND_APP_FUNCTION_SERVICE權限意味著只有系統認可的代理如Gemini才能預設調用你的功能。平台的安全措施是合理的。但隨著代理生態系統的成長,攻擊面也在擴大.

注意: 每個@AppFunction 像一個公開的 API 端點 — 驗證輸入,範圍輸出,記錄呼叫。這個註解很簡單;它所承擔的責任卻不簡單.

你實際上暴露的是什麼

這個讓開發者感到驚訝:你並沒有暴露源代碼,但你 實際上暴露的是你的應用程式的功能表面 — 這同樣伴隨著風險。

AppFunctions 會向外界揭露什麼:

  • 您的函數名稱如 createExpenseReportdeleteUserAccount 作為可發現的公開模式 — 任何擁有正確工具的人都可以列舉您的應用程式註冊了什麼
  • 您的參數類型揭露了您的內部數據模型。CreateExpenseParams 的形狀是可見的,不僅僅是它的名稱
  • 您的商業邏輯邊界 — 如果archiveAllRecords 作為一個 AppFunction 存在,你甚至在發布它的 UI 之前就宣傳了這項功能

需要考慮的真正攻擊場景:

  • 一個探測性應用程式列舉你的註冊函數,以逆向工程你的數據模型
  • 一個沒有內部驗證的 admin 級別函數被不受信任的代理調用 — 僅僅依靠宣告權限是不夠的
  • 競爭對手在您發布前會閱讀您的函數名稱,並且清楚知道即將推出什麼

該怎麼辦:

  • 絕不註冊一個沒有明確設計為代理可調用的函數 — 您的儲存庫中不是每個東西都值得一個@AppFunction
  • 在內部添加權限檢查 每個函數,無論是否具備顯示權限
  • 對於敏感操作使用通用名稱,以避免函數名本身洩露意圖
  • 在每次發布前審核 @AppFunction 注釋,就像審核一個公開的 REST API 標準一樣

Google I/O 2026 有許多令人興奮的宣布。Compose First 已經過期,非常歡迎。AI 開發工具非常實用。Android Automotive 是一條值得探索的真實職業道路.

但 AppFunctions 才是改變我們所說「Android 應用程式」意味的關鍵。它是潛力股。五年後,我認為我們會回顧 I/O 2026 作為轉變開始的時刻。

如果您今天開始讓代理調用您的功能,您將如何處理當前服務層中的幂等性?在評論中分享您的架構「噩夢」場景——我非常想聽聽它們。


相關會議:開發者主題演講 — Google I/O 2026