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

Android中使用OkHttp3无法连接WebSocket问题求助

Android端OkHttp3连接WebSocket失败无日志问题排查

我在服务器上部署了一个已验证可用的WebSocket,但用OkHttp3在Android端连接时失败,日志里完全没报错。我是Android开发新手,下面是我的Android端代码、Manifest文件,另外相同的WebSocket连接逻辑在普通Java项目里能正常运行。


Android端代码

package kean.pathfinder;

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.widget.Button;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapView;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Polyline;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.util.concurrent.atomic.AtomicReference;

import kean.pathfinder.websocket.WebListener;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.WebSocket;

public class MainActivity extends AppCompatActivity implements OnMapReadyCallback, LocationListener {

    private MapView map;

    private final Path path = new Path();
    private GoogleMap googleMap;
    private LocationManager locationManager;
    private WebSocket ws;
    private OkHttpClient client;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        map = findViewById(R.id.map);
        Button start = findViewById(R.id.start);
        Button undo = findViewById(R.id.undo);
        Button clear = findViewById(R.id.clear);

        client = new OkHttpClient();

        Request request = new Request.Builder().url("ws://myServer.ip").build();
        WebListener listener = new WebListener();
        ws = client.newWebSocket(request,listener);

        ws.send("Hi from android");

        ws.close(1000,"Session end");

        start.setOnClickListener(l -> {
            try {
                JSONObject object = new JSONObject();
                JSONArray array = new JSONArray();
                for (LatLng latLng : path.getPoints()){
                    JSONObject point = new JSONObject();
                    point.put("lat",latLng.latitude);
                    point.put("lng",latLng.longitude);
                    array.put(point);
                }
                object.put("points",array);
                ws.send(object.toString());
            } catch (JSONException e){
                e.printStackTrace();
            }
        });
        undo.setOnClickListener(l -> {
            path.undo();
            updatePoly();
        });
        clear.setOnClickListener(l -> {
            path.clear();
            updatePoly();
        });


        map.getMapAsync(this);
        map.onCreate(savedInstanceState);

        locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

        requestLocation();
    }

    public void onMapReady(@NonNull GoogleMap googleMap) {
        googleMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
        this.googleMap = googleMap;

        googleMap.setOnMapClickListener(l -> {
            path.add(l);
            updatePoly();
        });
    }

    private final AtomicReference<Polyline> polyline = new AtomicReference<>();
    private void updatePoly(){
        Polyline p = polyline.get();
        if (p != null) p.remove();
        polyline.set(googleMap.addPolyline(path.getPoly()));
    }

    public void onLocationChanged(@NonNull Location location) {
        LatLng latLng = new LatLng(location.getLatitude(),location.getLongitude());
        googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng,50));
        locationManager.removeUpdates(this);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == 1){
            requestLocation();
        }
    }

    private void requestLocation()
    {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.ACCESS_FINE_LOCATION},1);
            return;
        }
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 400L, 1000f, this);
    }

    @Override
    protected void onStart() {
        super.onStart();
        map.onStart();
    }

    @Override
    protected void onResume() {
        super.onResume();
        map.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
        map.onPause();
    }

    @Override
    protected void onStop() {
        super.onStop();
        map.onStop();
        ws.close(1000,"Session ended");
        client.dispatcher().executorService().shutdown();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        map.onDestroy();
    }

    @Override
    public void onSaveInstanceState(@NonNull Bundle outState, @NonNull PersistableBundle outPersistentState) {
        super.onSaveInstanceState(outState, outPersistentState);
        map.onSaveInstanceState(outState);
    }

    @Override
    public void onLowMemory() {
        super.onLowMemory();
        map.onLowMemory();
    }
}

Manifest文件

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.PathFinder"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <meta-data
                android:name="android.app.lib_name"
                android:value="" />
        </activity>

        <meta-data
            android:name="com.google.android.maps.v2.API_KEY"
            android:value="token" />

    </application>

</manifest>

普通Java项目测试代码(可正常运行)

package org.example;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.WebSocket;

public class Main {
    public static void main(String[] args) {
        OkHttpClient client = new OkHttpClient();

        Request request = new Request.Builder().url("ws://myServer.ip").build();
        // Empty class
        WebListener listener = new WebListener();
        WebSocket ws = client.newWebSocket(request,listener);

        ws.send("Hello World");

        ws.close(1000,"End");

        client.dispatcher().executorService().shutdown();
    }
}

问题解决要点

  1. 移除过早关闭WebSocket的代码:onCreate里创建WebSocket后立刻调用ws.close会直接终止连接,仅保留onStop中的关闭逻辑即可,避免连接未建立就被中断。
  2. 实现完整的WebSocketListener:空的WebListener无法反馈连接状态,必须重写关键方法获取日志:
public class WebListener extends WebSocketListener {
    private static final int NORMAL_CLOSURE_STATUS = 1000;

    @Override
    public void onOpen(WebSocket webSocket, Response response) {
        Log.d("WebSocket", "连接成功");
        webSocket.send("Hi from android"); // 连接成功后再发送消息
    }

    @Override
    public void onFailure(WebSocket webSocket, Throwable t, Response response) {
        Log.e("WebSocket", "连接失败", t);
    }

    @Override
    public void onMessage(WebSocket webSocket, String text) {
        Log.d("WebSocket", "收到消息: " + text);
    }

    @Override
    public void onClosing(WebSocket webSocket, int code, String reason) {
        webSocket.close(NORMAL_CLOSURE_STATUS, null);
        Log.d("WebSocket", "正在关闭: " + code + " / " + reason);
    }

    @Override
    public void onClosed(WebSocket webSocket, int code, String reason) {
        Log.d("WebSocket", "已关闭: " + code + " / " + reason);
    }
}
  1. 添加明文网络许可:Android 9+默认禁止明文WS请求,在Manifest的application标签里添加:
android:usesCleartextTraffic="true"
  1. 调整消息发送时机:不要在onCreate里直接调用ws.send,必须在onOpen回调确认连接成功后再发送,避免因连接未建立导致消息丢失。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 02:01:10