package main import ( "context" "encoding/json" "fmt" "io" "net/http" "net/url" "time" ) const ( apiBaseURL = "https://data.openinstall.com" apiKey = "a7596bc007f31a98ca551e33a75d3bb5997b0b94027c6e988d3c0af1" ) type APIResponse struct { Code int `json:"code"` Error *string `json:"error"` Body json.RawMessage `json:"body"` } type DistributionData struct { Key string `json:"key"` Value int64 `json:"value"` } func main() { fmt.Println("========================================") fmt.Println("测试 OpenInstall 新增设备分布接口") fmt.Println("========================================") fmt.Println() ctx := context.Background() // 获取当月数据 now := time.Now() startOfMonth := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) fmt.Printf("当月数据: %s 到 %s\n", startOfMonth.Format("2006-01-02"), now.Format("2006-01-02")) fmt.Println("========================================") // 测试各平台的数据 platforms := []struct { name string platform string }{ {"iOS", "ios"}, {"Android", "android"}, {"HarmonyOS", "harmony"}, } for _, p := range platforms { fmt.Printf("\n平台: %s\n", p.name) fmt.Println("----------------------------------------") // 获取总量 data, err := getDeviceDistribution(ctx, startOfMonth, now, p.platform, "total") if err != nil { fmt.Printf("❌ 失败: %v\n", err) continue } fmt.Println("✅ 成功获取数据:") for _, item := range data { fmt.Printf(" %s: %d\n", item.Key, item.Value) } } // 测试不同的 sumBy 参数 fmt.Println("\n========================================") fmt.Println("测试不同的分组方式 (iOS平台):") fmt.Println("========================================") sumByOptions := []string{ "total", // 总量 "system_version", // 系统版本 "app_version", // app版本 "brand_model", // 机型 } for _, sumBy := range sumByOptions { fmt.Printf("\nsumBy=%s:\n", sumBy) fmt.Println("----------------------------------------") data, err := getDeviceDistribution(ctx, startOfMonth, now, "ios", sumBy) if err != nil { fmt.Printf("❌ 失败: %v\n", err) continue } if len(data) == 0 { fmt.Println("⚠️ 无数据") continue } fmt.Println("✅ 数据:") for _, item := range data { fmt.Printf(" %s: %d\n", item.Key, item.Value) } } fmt.Println("\n========================================") fmt.Println("测试完成!") fmt.Println("========================================") } func getDeviceDistribution(ctx context.Context, startDate, endDate time.Time, platform, sumBy string) ([]DistributionData, error) { apiURL := fmt.Sprintf("%s/data/sum/growth", apiBaseURL) params := url.Values{} params.Add("apiKey", apiKey) params.Add("beginDate", startDate.Format("2006-01-02")) // 注意:使用 beginDate 而不是 startDate params.Add("endDate", endDate.Format("2006-01-02")) params.Add("platform", platform) // 平台过滤: ios, android, harmony params.Add("sumBy", sumBy) // 分组方式 params.Add("excludeDuplication", "0") // 不排重 fullURL := fmt.Sprintf("%s?%s", apiURL, params.Encode()) req, err := http.NewRequestWithContext(ctx, http.MethodGet, fullURL, nil) if err != nil { return nil, fmt.Errorf("failed to create request: %w", err) } client := &http.Client{Timeout: 10 * time.Second} resp, err := client.Do(req) if err != nil { return nil, fmt.Errorf("failed to send request: %w", err) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("failed to read response: %w", err) } var apiResp APIResponse if err := json.Unmarshal(body, &apiResp); err != nil { return nil, fmt.Errorf("failed to parse response: %w", err) } if apiResp.Code != 0 { errMsg := "unknown error" if apiResp.Error != nil { errMsg = *apiResp.Error } return nil, fmt.Errorf("API error (code=%d): %s", apiResp.Code, errMsg) } var distData []DistributionData if err := json.Unmarshal(apiResp.Body, &distData); err != nil { return nil, fmt.Errorf("failed to parse distribution data: %w", err) } return distData, nil }