You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Retrofit2在Android模拟器正常,签名APK调用GPT接口报异常

问题:签名APK中Retrofit调用OpenAI ChatGPT-3.5 Turbo API失败

在Android Java聊天应用中使用Retrofit调用OpenAI接口,模拟器和调试设备上运行正常,但生成签名APK后调用API时抛出java.lang.IllegalArgumentException,错误信息如下:

java.lang.IllegalArgumentException: Unable to create call adapter for interface d6.g for method a.a...
java.lang.IllegalArgumentException: Call return type must be parameterized as Call or Call<? extends Foo>...

问题原因

签名APK默认开启代码混淆,Retrofit核心类、自定义API接口、响应实体类被混淆重命名,导致Retrofit无法识别参数化的Call<ChatCompletionResponse>类型,从而抛出适配器创建失败的异常。

解决方案

1. 添加混淆规则到proguard-rules.pro

在项目的proguard-rules.pro文件中添加以下规则,避免Retrofit、OkHttp、Gson及自定义相关类被混淆:

# Retrofit
-keepattributes Signature, InnerClasses, EnclosingMethod
-keep class retrofit2.** { *; }
-keep interface retrofit2.** { *; }
-keepclasseswithmembers class * {
    @retrofit2.http.* <methods>;
}

# OkHttp
-keep class okhttp3.** { *; }
-keep interface okhttp3.** { *; }
-dontwarn okhttp3.**

# Gson
-keepattributes *Annotation*
-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.stream.** { *; }

# 自定义API接口和响应实体类(替换为实际包名)
-keep class com.yourpackage.APIInterface { *; }
-keep class com.yourpackage.ChatCompletionResponse { *; }
-keep class com.yourpackage.ChatCompletionResponse$* { *; } # 保留内部类

2. 优化请求体写法(可选)

原代码手动构建RequestBody的方式可简化,直接用Gson将请求对象转为RequestBody,减少手动拼接JSON的错误:
首先创建请求实体类:

public class ChatRequest {
    private String model;
    private List<Message> messages;

    public ChatRequest(String model, List<Message> messages) {
        this.model = model;
        this.messages = messages;
    }

    public static class Message {
        private String role;
        private String content;

        public Message(String role, String content) {
            this.role = role;
            this.content = content;
        }
    }
}

修改sendRequest方法:

private void sendRequest(String query) {
    ChatRequest.Message message = new ChatRequest.Message("system", query);
    List<ChatRequest.Message> messageList = Collections.singletonList(message);
    ChatRequest request = new ChatRequest("gpt-3.5-turbo", messageList);

    RequestBody requestBody = RequestBody.create(
        GsonConverterFactory.create().getGson().toJson(request),
        MediaType.parse("application/json")
    );

    Call<ChatCompletionResponse> call = RetrofitInstance.getInstance().apiInterface.getData(requestBody);
    // 后续回调逻辑不变
}

3. 验证签名APK配置

确保Module级别的build.gradle中release配置正确引用混淆规则:

android {
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

相关代码

请求函数

private void sendRequest(String query) {
    JSONObject jsonObject = new JSONObject();
    try {
        jsonObject.put("model","gpt-3.5-turbo");
        JSONArray jsonArray = new JSONArray();
        JSONObject jsonObject1 = new JSONObject();
        jsonObject1.put("role","system");
        jsonObject1.put("content",query);
        jsonArray.put(0, jsonObject1);
        jsonObject.put("messages",jsonArray);

    } catch (JSONException e) {
        Log.d(TAG,e.getMessage());
        throw new RuntimeException(e);
    }
    RequestBody requestBody = new RequestBody() {
        @Override
        public MediaType contentType() {
            return MediaType.parse("application/json");
        }

        @Override
        public void writeTo(BufferedSink sink) throws IOException {
            sink.writeUtf8(jsonObject.toString());
        }
    };
    Call<ChatCompletionResponse> call = RetrofitInstance.getInstance().apiInterface.getData(requestBody);
    call.enqueue(new Callback<ChatCompletionResponse>() {
        @Override
        public void onResponse(@NonNull Call<ChatCompletionResponse> call, @NonNull Response<ChatCompletionResponse> response) {
            if(response.isSuccessful()){
                assert response.body() != null;
                String content = response.body().getChoices()[0].getMessage().getContent();
                TextMessage textMessage = new TextMessage(user.getUid(),content, CometChatConstants.RECEIVER_TYPE_USER);
                textMessage.setSender(user);
                addMessage(textMessage);
                setIndicator(false);
            }
        }

        @Override
        public void onFailure(@NonNull Call<ChatCompletionResponse> call, @NonNull Throwable t) {
            Log.d(TAG,"failurse occued" + t.getMessage());
            String msg = "Request failed !!";
            TextMessage textMessage = new TextMessage(logedinuser.getUid(),msg, CometChatConstants.RECEIVER_TYPE_USER);
            textMessage.setSender(logedinuser);
            addMessage(textMessage);
        }
    });
}

RetrofitInstance.java

public class RetrofitInstance {
    public static RetrofitInstance instance;
    public APIInterface apiInterface;
    static String BASE_URL = "https://api.openai.com/v1/chat/";
    RetrofitInstance(){
        OkHttpClient client = new OkHttpClient.Builder()
                .addInterceptor(new Interceptor() {
                    @NonNull
                    @Override
                    public Response intercept(@NonNull Chain chain) throws IOException {
                        Request newRequest = chain.request().newBuilder()
                                .addHeader("Content-Type", "application/json")
                                .addHeader("Authorization", "Bearer " + AppKeys.GPT_TOKEN )
                                .build();
                        return chain.proceed(newRequest);
                    }
                })
                .build();


        apiInterface = new Retrofit.Builder()
                .client(client)
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build().create(APIInterface.class);
    }
    public static RetrofitInstance getInstance(){
        if(instance == null){
            instance = new RetrofitInstance();
        }
        return instance;
    }
}

APIInterface.java

public interface APIInterface {
    @POST("completions")
    Call<ChatCompletionResponse> getData(
            @Body RequestBody body
    );
}

ChatCompletionResponse.java

public class ChatCompletionResponse {
    public String getId() {
        return id;
    }

    public String getObject() {
        return object;
    }

    public long getCreated() {
        return created;
    }

    public String getModel() {
        return model;
    }

    public UsageData getUsage() {
        return usage;
    }

    public Choice[] getChoices() {
        return choices;
    }

    @SerializedName("id")
    private String id;

    public void setId(String id) {
        this.id = id;
    }

    public void setObject(String object) {
        this.object = object;
    }

    public void setCreated(long created) {
        this.created = created;
    }

    public void setModel(String model) {
        this.model = model;
    }

    public void setUsage(UsageData usage) {
        this.usage = usage;
    }

    public void setChoices(Choice[] choices) {
        this.choices = choices;
    }

    @SerializedName("object")
    private String object;

    @SerializedName("created")
    private long created;

    public ChatCompletionResponse(String id, String object, long created, String model, UsageData usage, Choice[] choices) {
        this.id = id;
        this.object = object;
        this.created = created;
        this.model = model;
        this.usage = usage;
        this.choices = choices;
    }

    @SerializedName("model")
    private String model;

    @SerializedName("usage")
    private UsageData usage;

    @SerializedName("choices")
    private Choice[] choices;

    public static class UsageData {
        @SerializedName("prompt_tokens")
        private int promptTokens;

        @SerializedName("completion_tokens")
        private int completionTokens;

        @SerializedName("total_tokens")
        private int totalTokens;

        // Getters and setters
    }

    public static class Choice {
        public Choice(Message message, String finishReason, int index) {
            this.message = message;
            this.finishReason = finishReason;
            this.index = index;
        }

        public void setMessage(Message message) {
            this.message = message;
        }

        public void setFinishReason(String finishReason) {
            this.finishReason = finishReason;
        }

        public void setIndex(int index) {
            this.index = index;
        }

        @SerializedName("message")
        private Message message;

        public Message getMessage() {
            return message;
        }

        public String getFinishReason() {
            return finishReason;
        }

        public int getIndex() {
            return index;
        }

        @SerializedName("finish_reason")
        private String finishReason;

        @SerializedName("index")
        private int index;

        // Getters and setters
    }

    public static class Message {
        @SerializedName("role")
        private String role;

        public String getContent() {
            return content;
        }

        public Message(String role, String content) {
            this.role = role;
            this.content = content;
        }

        public void setRole(String role) {
            this.role = role;
        }

        public void setContent(String content) {
            this.content = content;
        }

        @SerializedName("content")
        private String content;

        // Getters and setters
    }
}

内容的提问来源于stack exchange,提问作者SHIVA VERMA

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 20:07:03