SDK 的最后一公里——如何通过技术文档提升函数传参体验

在调用 SDK 中的方法时,绝大部分情况下都涉及传参。传参的过程中,一般会涉及以下问题:

  • 获取参数所需的值。
  • 参数取值范围和对应的 SDK 行为。

取值范围和对应行为一般都会在参考文档中有详细解释。但是很多情况下,文档工程师会忽视在文档中说明如何获取参数所需的值。因为对于 API 本身的描述是基于 SDK 的开发人员提供的信息,这些信息虽然可以充分说明 API 的本身逻辑,却在某些情况下缺少了重要的背景信息。

示例一:Android 设备的屏幕共享功能

以一个第三方音视频 SDK 的 startScreenCapture 方法为例。该方法可以在 Android 客户端录制屏幕:

public abstract int startScreenCapture(
      Intent mediaProjectionPermissionResultData, ScreenCaptureParameters parameters);
复制代码

其中,parameters 参数的传参都是简单的数值,开发者仅需要了解如何调节分辨率、帧率和码率。

public class ScreenCaptureParameters {
  private VideoDimensions videoDimensions;
  private int frameRate;
  private int bitrate;

  public ScreenCaptureParameters() {
    videoDimensions = new VideoDimensions(1080, 1920);
    frameRate = 5;
    bitrate = 4098;
  }
  
  ...
}
复制代码

mediaProjectionPermissionResultData 参数的传参却没有这么直观。从接口类型上看,是 Intent 类。对于 Intent,作为 Android 开发者当然是非常熟悉的。

An intent is an abstract description of an operation to be performed. It can be used with startActivity to launch an ActivitybroadcastIntent to send it to any interested BroadcastReceiver components, and Context.startService(Intent) or Context.bindService(Intent, ServiceConnection, int) to communicate with a background Service.

但是这个 Intent 到底是谁的 intent,又从哪里获得呢?其实完整的逻辑是这样的:

  1. 调用 Android Platform API 的 createScreenCaptureIntent 为屏幕共享 activity 创建 Intent。
  2. 调用 Android Platform API 的 startActivityForResult 开启屏幕共享 activity。
  3. 在 Android Platform API 的 onActivityResult 回调中,调用第三方音视频 SDK 的 startScreenCapture 方法并在 mediaProjectionPermissionResultData 参数中并传入 data 参数的值。
protected void onActivityResult (int requestCode, 
                int resultCode, 
                Intent data)
复制代码

这些逻辑就组成了一篇完整的开发者指南。没有这篇开发者指南,恐怕开发者看到这个接口都会一脸懵。当然,我们不排除确实有高手可以通过 mediaProjectionPermissionResultData 这个参数名猜到需要填的参数。但作为 ToB 业务,让开发者猜并不是一种很好的付费体验。

可以看到,其实大量的工作都需要开发者自己调用 Android SDK 的方法实现。当然,这也说明 SDK 本身也需要通过迭代来提高易用性。但与此同时,技术文档可以有效地为此类接口的最后一公里提供有力协助。

示例二:服务端鉴权秘钥生成示例

某技术文档有一段鉴权逻辑是这么说的:

在请求认证的代码中,填入客户 ID (key) 和客户密钥 (secret),生成一个使用 Base64 算法编码的凭证,并在 HTTP 请求头部的 Authorization 字段中填入该凭证。

这一段描述非常模糊。开发者看到这里,也不知道自己的请求究竟要怎么写才能生成这个凭证。但如果来一段能跑通的示例代码就好多了:

import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.Base64;


// 基于 Java 实现的 HTTP 基本认证示例,使用 RTC 的服务端 RESTful API
public class Base64Encoding {

    public static void main(String[] args) throws IOException, InterruptedException {

        // 客户 ID
        final String customerKey = "Your customer key";
        // 客户密钥
        final String customerSecret = "Your customer secret";

        // 拼接客户 ID 和客户密钥并使用 base64 编码
        String plainCredentials = customerKey + ":" + customerSecret;
        String base64Credentials = new String(Base64.getEncoder().encode(plainCredentials.getBytes()));
        // 创建 authorization header
        String authorizationHeader = "Basic " + base64Credentials;

        HttpClient client = HttpClient.newHttpClient();

        // 创建 HTTP 请求对象
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://api.agora.io/dev/v1/projects"))
                .GET()
                .header("Authorization", authorizationHeader)
                .header("Content-Type", "application/json")
                .build();
        // 发送 HTTP 请求
        HttpResponse<String> response = client.send(request,
                HttpResponse.BodyHandlers.ofString());

        System.out.println(response.body());
    }
}
复制代码

上面的示例代码是 Java 的,如果再增加几个服务端常用的语言就更好了。下面来一段 Golang 的:

package main

import (
"fmt"
"strings"
"net/http"
"io/ioutil"
"encoding/base64"
)

// 基于 Golang 实现的 HTTP 基本认证示例,使用 RTC 的服务端 RESTful API
func main() {

// 客户 ID
customerKey := "Your customer key"
// 客户密钥
customerSecret := "Your customer secret"

// 拼接客户 ID 和客户密钥并使用 base64 进行编码
plainCredentials := customerKey + ":" + customerSecret
base64Credentials := base64.StdEncoding.EncodeToString([]byte(plainCredentials))

url := "https://api.agora.io/dev/v1/projects"
method := "GET"

payload := strings.NewReader(``)

client := &http.Client {
}
req, err := http.NewRequest(method, url, payload)

if err != nil {
    fmt.Println(err)
    return
}
// 增加 Authorization header
req.Header.Add("Authorization", "Basic " + base64Credentials)
req.Header.Add("Content-Type", "application/json")

// 发送 HTTP 请求
res, err := client.Do(req)
if err != nil {
    fmt.Println(err)
    return
}
defer res.Body.Close()

body, err := ioutil.ReadAll(res.Body)
if err != nil {
    fmt.Println(err)
    return
}
fmt.Println(string(body))
}
复制代码

这样的说明就没有任何歧义了。非常清晰明了。

总结

丝滑顺畅的最后一公里体验,可以为 ToB 产品带来巨大的竞争优势。SDK 本身的设计优化当然是非常重要的,但可以提供详细背景信息,打通整个使用流程的技术文档也同样重要。否则,随着用户数量的增加,客户成功部门的电话可能会被打爆。SDK 研发也会疲于应付各种客户问题,无心开发。而糟糕的接入体验显然也会带来客户的流失,这甚至会成为一个恶性循环。

猜你喜欢

转载自juejin.im/post/7105782741534244871
SDK