package main import ( "context" "encoding/json" "fmt" "io" "net/http" "net/url" "time" ) const ( // OpenInstall 数据接口基础 URL apiBaseURL = "https://data.openinstall.com" // 您的 ApiKey (数据接口密钥) apiKey = "a7596bc007f31a98ca551e33a75d3bb5997b0b94027c6e988d3c0af1" ) // 通用响应结构 type APIResponse struct { Code int `json:"code"` Error *string `json:"error"` Body json.RawMessage `json:"body"` } // 新增安装数据 type GrowthData struct { Date string `json:"date"` Visit int64 `json:"visit"` // 点击量 Click int64 `json:"click"` // 访问量 Install int64 `json:"install"` // 安装量 Register int64 `json:"register"` // 注册量 SurviveD1 int64 `json:"survive_d1"` // 1日留存 SurviveD7 int64 `json:"survive_d7"` // 7日留存 SurviveD30 int64 `json:"survive_d30"` // 30日留存 } // 渠道列表数据 type ChannelData struct { ChannelCode string `json:"channelCode"` ChannelName string `json:"channelName"` LinkURL string `json:"linkUrl"` CreateTime string `json:"createTime"` GroupName string `json:"groupName"` } func main() { fmt.Println("========================================") fmt.Println("OpenInstall API 测试程序") fmt.Println("========================================") fmt.Printf("ApiKey: %s\n", apiKey) fmt.Printf("API Base URL: %s\n", apiBaseURL) fmt.Println() ctx := context.Background() // 测试1: 获取新增安装数据(最近7天) fmt.Println("测试1: 获取新增安装数据(最近7天)") fmt.Println("========================================") testGrowthData(ctx, 7) fmt.Println() // 测试2: 获取新增安装数据(最近30天) fmt.Println("测试2: 获取新增安装数据(最近30天)") fmt.Println("========================================") testGrowthData(ctx, 30) fmt.Println() // 测试3: 获取渠道列表 fmt.Println("测试3: 获取渠道列表") fmt.Println("========================================") testChannelList(ctx) fmt.Println() fmt.Println("========================================") fmt.Println("测试完成!") fmt.Println("========================================") } // 测试获取新增安装数据 func testGrowthData(ctx context.Context, days int) { // 设置查询时间范围 endDate := time.Now() startDate := endDate.AddDate(0, 0, -days) // 构建 API URL apiURL := fmt.Sprintf("%s/data/event/growth", apiBaseURL) params := url.Values{} params.Add("apiKey", apiKey) params.Add("startDate", startDate.Format("2006-01-02")) params.Add("endDate", endDate.Format("2006-01-02")) params.Add("statType", "daily") // daily = 按天统计, hourly = 按小时统计, total = 合计 fullURL := fmt.Sprintf("%s?%s", apiURL, params.Encode()) fmt.Printf("请求 URL: %s\n", fullURL) body, statusCode, err := makeRequest(ctx, fullURL) if err != nil { fmt.Printf("❌ 请求失败: %v\n", err) return } fmt.Printf("HTTP 状态码: %d\n", statusCode) if statusCode == 200 { // 解析响应 var apiResp APIResponse if err := json.Unmarshal(body, &apiResp); err != nil { fmt.Printf("❌ JSON 解析失败: %v\n", err) printRawResponse(body) return } if apiResp.Code == 0 { fmt.Println("✅ 成功获取数据!") // 解析业务数据 var growthData []GrowthData if err := json.Unmarshal(apiResp.Body, &growthData); err != nil { fmt.Printf("⚠️ 业务数据解析失败: %v\n", err) printRawResponse(body) return } // 格式化输出数据 fmt.Printf("\n共获取 %d 天的数据:\n", len(growthData)) fmt.Println("----------------------------------------") for _, data := range growthData { fmt.Printf("日期: %s\n", data.Date) fmt.Printf(" 访问量(visit): %d\n", data.Visit) fmt.Printf(" 点击量(click): %d\n", data.Click) fmt.Printf(" 安装量(install): %d\n", data.Install) fmt.Printf(" 注册量(register): %d\n", data.Register) fmt.Printf(" 1日留存: %d\n", data.SurviveD1) fmt.Printf(" 7日留存: %d\n", data.SurviveD7) fmt.Printf(" 30日留存: %d\n", data.SurviveD30) fmt.Println("----------------------------------------") } } else { errMsg := "未知错误" if apiResp.Error != nil { errMsg = *apiResp.Error } fmt.Printf("❌ API 返回错误 (code=%d): %s\n", apiResp.Code, errMsg) printRawResponse(body) } } else { fmt.Printf("❌ HTTP 请求失败\n") printRawResponse(body) } } // 测试获取渠道列表 func testChannelList(ctx context.Context) { // 构建 API URL apiURL := fmt.Sprintf("%s/data/channel/list", apiBaseURL) params := url.Values{} params.Add("apiKey", apiKey) params.Add("pageNum", "0") params.Add("pageSize", "20") fullURL := fmt.Sprintf("%s?%s", apiURL, params.Encode()) fmt.Printf("请求 URL: %s\n", fullURL) body, statusCode, err := makeRequest(ctx, fullURL) if err != nil { fmt.Printf("❌ 请求失败: %v\n", err) return } fmt.Printf("HTTP 状态码: %d\n", statusCode) if statusCode == 200 { // 解析响应 var apiResp APIResponse if err := json.Unmarshal(body, &apiResp); err != nil { fmt.Printf("❌ JSON 解析失败: %v\n", err) printRawResponse(body) return } if apiResp.Code == 0 { fmt.Println("✅ 成功获取渠道列表!") // 直接打印原始数据 printJSONResponse(apiResp.Body) } else { errMsg := "未知错误" if apiResp.Error != nil { errMsg = *apiResp.Error } fmt.Printf("❌ API 返回错误 (code=%d): %s\n", apiResp.Code, errMsg) printRawResponse(body) } } else { fmt.Printf("❌ HTTP 请求失败\n") printRawResponse(body) } } // 发送 HTTP 请求 func makeRequest(ctx context.Context, url string) ([]byte, int, error) { req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { return nil, 0, fmt.Errorf("创建请求失败: %w", err) } client := &http.Client{ Timeout: 10 * time.Second, } resp, err := client.Do(req) if err != nil { return nil, 0, fmt.Errorf("发送请求失败: %w", err) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return nil, resp.StatusCode, fmt.Errorf("读取响应失败: %w", err) } return body, resp.StatusCode, nil } // 打印原始响应 func printRawResponse(body []byte) { fmt.Println("\n原始响应内容:") var prettyJSON map[string]interface{} if err := json.Unmarshal(body, &prettyJSON); err == nil { formatted, _ := json.MarshalIndent(prettyJSON, "", " ") fmt.Println(string(formatted)) } else { fmt.Println(string(body)) } } // 打印 JSON 响应 func printJSONResponse(data json.RawMessage) { var prettyJSON interface{} if err := json.Unmarshal(data, &prettyJSON); err == nil { formatted, _ := json.MarshalIndent(prettyJSON, "", " ") fmt.Println(string(formatted)) } else { fmt.Println(string(data)) } }