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

如何让公共蓝牙包方法在所有子包中可访问且无需设为public

解决方案:在Android中实现包结构隔离且子包可访问核心方法

我完全懂你的困扰——既要保持代码结构清晰,又不想把核心蓝牙方法暴露成public,还要让SPP、HDP、BTLE这些子包能复用公共包的通用逻辑。结合Java/Kotlin的访问权限规则和Android的代码组织方式,给你几个实用的解决方案:

1. 用Kotlin的internal权限(推荐,如果你用Kotlin开发)

Kotlin的internal修饰符可以让方法/类在同一个模块内的所有包可见,但对模块外完全隐藏。这完美匹配你的需求:

  • 公共蓝牙包的核心方法设为internal,不用暴露给外部
  • SPP、HDP、BTLE子包和公共包同属一个模块,直接就能访问这些internal方法
  • 包结构保持清晰,各自负责不同的蓝牙协议实现

示例代码:

// 公共包:com.yourapp.bluetooth.core
internal class CoreBluetooth(private val context: Context, private val receiver: BroadcastReceiver) {
    internal fun connectDevice(address: String) {
        // 通用蓝牙连接逻辑
    }

    internal fun scanDevices() {
        // 通用扫描逻辑
    }
}

// SPP子包:com.yourapp.bluetooth.spp
class SppBluetooth(context: Context, receiver: BroadcastReceiver) {
    private val core = CoreBluetooth(context, receiver)

    fun connectSppDevice(address: String) {
        // 直接调用公共包的internal方法
        core.connectDevice(address)
        // 加上SPP专属的连接逻辑
    }
}

2. 优化继承方案,解决Context和BroadcastReceiver问题

你之前尝试继承遇到的问题,其实可以通过构造函数传递依赖来解决,不用把核心方法设为public:

  • 公共包的基类把Context和BroadcastReceiver通过构造函数接收并持有
  • 基类的通用方法设为protected,子类(子包中的类)可以直接访问
  • 每个子包的类继承基类,初始化时传入所需的Context和Receiver

示例代码(Java):

// 公共包:com.yourapp.bluetooth.core
public abstract class BaseBluetooth {
    protected final Context context;
    protected final BroadcastReceiver bluetoothReceiver;

    // 构造函数接收依赖,子类必须调用
    protected BaseBluetooth(Context context, BroadcastReceiver receiver) {
        this.context = context;
        this.bluetoothReceiver = receiver;
    }

    // 通用方法,protected修饰,仅子类可见
    protected void connectGeneric(String address) {
        // 通用连接逻辑
        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
        BluetoothDevice device = adapter.getRemoteDevice(address);
        // ...
    }
}

// SPP子包:com.yourapp.bluetooth.spp
public class SppBluetooth extends BaseBluetooth {
    public SppBluetooth(Context context, BroadcastReceiver receiver) {
        super(context, receiver); // 传递依赖给父类
    }

    public void connectSpp(String address) {
        // 调用父类的protected方法
        connectGeneric(address);
        // SPP专属逻辑:比如创建RFCOMM通道
        // ...
    }
}

这种方案既保持了继承的代码复用性,又解决了Context和Receiver的初始化问题,同时核心方法不会暴露给外部包。

3. 接口+工厂模式,隐藏实现细节

如果不想用继承,也可以用接口定义通用行为,把具体实现放在公共包内,通过工厂方法提供实例给子包:

  • 公共包定义public的接口,暴露需要的通用方法
  • 公共包内创建包级私有(默认权限)的实现类,实现接口逻辑
  • 公共包提供public的工厂类,负责创建实现类的实例
  • 子包通过接口访问通用逻辑,完全看不到实现细节

示例代码(Java):

// 公共包:com.yourapp.bluetooth.core
public interface BluetoothCore {
    void connectDevice(String address);
    void startScan();
}

// 包级私有实现类,仅核心包内可见
class BluetoothCoreImpl implements BluetoothCore {
    private Context context;
    private BroadcastReceiver receiver;

    BluetoothCoreImpl(Context context, BroadcastReceiver receiver) {
        this.context = context;
        this.receiver = receiver;
    }

    @Override
    public void connectDevice(String address) {
        // 通用连接逻辑
    }

    @Override
    public void startScan() {
        // 通用扫描逻辑
    }
}

// 公共工厂类,对外提供实例
public class BluetoothCoreFactory {
    public static BluetoothCore create(Context context, BroadcastReceiver receiver) {
        return new BluetoothCoreImpl(context, receiver);
    }
}

// SPP子包:com.yourapp.bluetooth.spp
public class SppBluetooth {
    private BluetoothCore core;

    public SppBluetooth(Context context, BroadcastReceiver receiver) {
        core = BluetoothCoreFactory.create(context, receiver);
    }

    public void connectSppDevice(String address) {
        core.connectDevice(address);
        // SPP专属逻辑
    }
}

这种方案的好处是完全解耦了子包和公共包的实现,核心逻辑被隐藏,同时结构清晰。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:35:30