Android AI解放生产力(五)实战:解放写API接口的繁琐工作

公司当前项目使用的是Apifox作为API调试/文档工具,所以以这个为例。市面上的工具应该都逐步开放了AI能力,需要关注一下,只要能提供原始数据就行,不能的话那也没办法喂给AI。

上一篇已经让AI写UI了,这一篇让AI写接口请求。首先思考一下可能碰到的问题。

一、可能遇到的问题

默认网络请求用的retrofit,其它也是一通百通。

1、问题一:适配请求头

项目中网络请求的拦截器已经定义了请求头,读取的原始数据如何关联?答案就是在skill中告诉AI,并让它模仿你的代码写。

2、问题二:适配请求参数中有一些公共部分

项目中网络请求的拦截器已经定义了一些公共请求参数,读取的原始数据如何关联?例如:

kotlin 复制代码
{
    "app": {
        "locale": "{{locale}}",
        "tid": "{{terminal_id}}",
        "platform": "{{platform}}"
    },
    "data": {
        //每个接口只有这里有差异
    }
}

只有data块中有差异。答案其实同上,skill中告诉AI,并让它模仿你的代码。

3、问题三:返回数据脱壳

例如项目中的壳是这样:

kotlin 复制代码
data class ApiResponse<T>(
    val code: Int,
    val msg: String,
    val data: T
) : BaseResponse<T>() {...}

那我们需要的解析的Data Class可能只需要脱壳的部分,如何让AI知道?答案也同上,skill中告诉AI,并让它模仿你的代码。

4、问题四:viewmodel中网络请求如何写

道理同上。

5、问题五:代码放在哪个文件

这个问题的解答要看情况了,我们先看下面只给代码的示例,最后再探讨一下这个问题。

二、获取接口原始数据

这一步依赖MCP的开放能力,后端兄弟接口怎么定义的,字段怎么写的,Android如何封装Data Class都依赖这些原始数据。接下来看通过Apifox如何办到的。

Apifox的MCP现阶段还不能集成到Codex中使用,启动的时候会报错:

kotlin 复制代码
⚠ MCP client for `apifox_api_docs` failed to start: MCP startup failed: handshaking with MCP server failed: connection closed: initialize response
⚠ MCP startup incomplete (failed: apifox_api_docs)

原因是Apifox的MCP返回不符合Codex定义的规范。

那换其他方式,打开Apifox终端(当前V版本2.7.58 (2.7.58)),选择需要生成代码的接口:

如上操作,可以得到复制的一段信息如下:

kotlin 复制代码
请访问以下链接获取接口"天气信息V3"的接口定义信息:https://api.apifox.cn/temp-links/api/%E5%A4%A9%E6%B0%6%81%AFv3-253061517?t=e0be3ab5-e8bf-4ec2-be81-f1489

这样我们就拿到了接口的原始数据链接。

三、如何编辑skills

这一步跟项目强关联,因为每个项目写法都不一样,文件不一样,所以skill的写法因项目而异,下面贴一份剔除敏感信息后的skill,抛砖引玉:

kotlin 复制代码
---
name: api_to_request
description: 请访问链接获取接口定义信息。
---
## 请访问链接获取接口定义信息,给出如下要求的代码:

### 1、代码一:生成retrofit接口定义
`java/api` 文件夹内是定义的retrofit api 请求的接口,例如其中的一例:

/**
 * 获取Camera Event事件
 */
@POST("/v1/iot/camera/discoverXXX")
suspend fun discoverXxx(@Body request: Request): ApiResponse<Response?>

请按照链接中的请求类型给出类似上面的接口定义。

### 2、代码二:给出请求的@Body
一般的请求数据示例是下面这样的:

{
    "data": {
        "dev_id": "xxx"
    },
    "app": {
        "locale": "en_AU",
        "tid": "8AE4EC1E36904B869D03FC9BABE4C087",
        "alias": "Kevin 的 A52",
        "platform": "foxx"
    }
}

为了避免每次都给出重复的参数,我在retrofit添加了一个拦截器,请参考`AddPublicParamsInterceptor.kt`文件,这里是添加公共请求参数的地方。所以@Body中只需要给出data节点的内容即可,如果data节点内的内容为空,那就不需要给出任何参数,因为`AddPublicParamsInterceptor.kt`中会默认添加`{}`.

### 3、代码三:给出返回的response
返回的数据使用`ApiResponse.kt`剥壳,所以给出的response数据应该是剥壳后的数据,一般是一个data class类。请参考`java/data`文件夹内其他response的写法给出。

### 4、代码四:viewmodel中实际请求的代码
viewmodel中实际请求的代码请参考下面的代码给出:

    /**
     * 获取设备同步授权码
     */
    fun syncAppDevice(
        buffer: MeshBanBindBuffer,
        success: (Any?) -> Unit,
        fail: (ApiHttpExceptionResponse<Any?>) -> Unit,
        error: (AppException) -> Unit
    ) {
        val request = SyncAppDeviceRequest(...)
        requestWithHttpException({ apiService.syncAppDevice(request) }, success = {
            success(it)
        }, fail = {
            fail(it)
        }, error = {
            error(it)
        })
    }

根据项目情况可以写的更丰富,更详细。

Apifox复制链接的内容因为匹配skill的description,所以给出链接就可以触发上面的skill。Codex生成的代码如下(剔除了敏感信息):

kotlin 复制代码
• 使用 api_to_request 技能,因为需要从接口文档生成 Retrofit 请求、请求体、响应体与 ViewModel 调用代码。(api.apifox.cn (https://api.apifox.cn/temp-links/api/
  %E5%A4%A9%E6%F%A1%E6%81%AFv3-253061517?t=e0be3ab5-e8bf-4ec2-be81-f148d9))

  代码一:Retrofit 接口定义(api.apifox.cn (https://api.apifox.cn/temp-links/api/%E5%A4%A9%E6%A1%E6%81%AFv3-253061517?t=e0be3ab5-e8bf-4ec2-be81-
  f14569))

  /**
   * 天气信息V3
   */
  @POST("/v1/iot/weather/getCurrentInfo")
  suspend fun getCurrentInfoV3(@Body request: WeatherInfoV3Request): ApiResponse<WeatherInfoV3Response?>

  代码二:@Body(仅 data 节点)(api.apifox.cn (https://api.apifox.cn/temp-links/api/%E5%A4%A9%E6%%E6%81%AFv3-253061517?t=e0be3ab5-e8bf-4ec2-be81-
  f8569))

  data class WeatherInfoV3Request(
      var lon: Double,
      var lat: Double,
      var unit: String = "IMPERIAL" // METRIC / IMPERIAL
  )

  代码三:Response(剥壳后的 data)(api.apifox.cn (https://api.apifox.cn/temp-links/api/%E5%A4%A9%E6%F%A1%E6%81%AFv3-253061517?t=e0be3ab5-e8bf-4ec2-
  be81-f18569))

  data class WeatherInfoV3Response(
      var day: Boolean?,
      var weather: WeatherV3?,
      var temperature: Double?,
      var wind: Double?,
      var pressure: Double?,
      var humidity: Double?,
      var aqi: String?
  )

  data class WeatherV3(
      var condition: String?,
      var icon: String?
  )

  代码四:ViewModel 中实际请求代码(api.apifox.cn (https://api.apifox.cn/temp-links/api/%E5%A4%A9%%A1%E6%81%AFv3-253061517?t=e0be3ab5-e8bf-4ec2-
  be81-f1469))

  /**
   * 获取天气信息V3
   */
  fun getCurrentInfoV3(
      lon: Double,
      lat: Double,
      unit: String = "IMPERIAL",
      success: (WeatherInfoV3Response?) -> Unit,
      fail: (ApiHttpExceptionResponse<Any?>) -> Unit,
      error: (AppException) -> Unit
  ) {
      val request = WeatherInfoV3Request(
          lon = lon,
          lat = lat,
          unit = unit
      )
      requestWithHttpException({ homeManagementApiService.getCurrentInfoV3(request) }, success = {
          success(it)
      }, fail = {
          fail(it)
      }, error = {
          error(it)
      })
  }

生成的代码可用度极高,很大程度上解放了生产力。

四、AI的放权

AI生成的代码可用度这么高,那是不是应该放权直接让AI写文件呢?

1、如果是一个新项目,定义好项目架构后就大胆的让AI生成文件自己写代码吧,能"摸鱼"就别动手,人生苦短我用AI。

2、如果是一个成熟度高的项目,建议以小颗粒度的形式让AI生成或修改文件代码,这样影响的范围可控,git提交的时候请仔细审查AI生成的代码。

3、如果是一个成熟度高的项目,修改的需求复杂,牵扯面广,或者公司规定不让AI写代码只让辅助参考,那还是开只读模式自己写吧。

回到最上面的问题五:代码放哪个文件?

答案就简单了。

  • 项目架构清晰,让AI干活,可以完全让AI自主决策,后续自己调整。
  • 可以在skill中添加提示加以引导,让AI放哪个文件/目录。
  • 只读模式,自己处理AI生成的代码,前期可以开只读熟悉AI的使用,等熟练后就可以让AI自己写文件了。
相关推荐
阿巴斯甜10 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker10 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq952711 小时前
Andorid Google 登录接入文档
android
黄林晴12 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab1 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿1 天前
Android MediaPlayer 笔记
android
Jony_1 天前
Android 启动优化方案
android
阿巴斯甜1 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇1 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_1 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android