docs(webrtc_controller_flutter): 更新项目文档以反映重构后的架构
AGENTS.md 与 README.md 同步更新:根据实际代码结构重写目录树、技术栈、架构分层及编码规范,移除旧版内联示例并补充新的开发约定与代码生成命令。
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
import 'package:fixnum/fixnum.dart';
|
||||
import 'package:webrtc_controller_flutter/core/proto/control_message.pb.dart';
|
||||
|
||||
/// 控制指令构造工具,对应 Android 端 RemoteTouchView 的指令格式。
|
||||
///
|
||||
/// 指令通过 DataChannel 以 protobuf 二进制([ControlMessage])发送,
|
||||
/// 被控端(WebRTCControlled)的 InputCommandHandler 负责解析执行。
|
||||
class ControlCommands {
|
||||
ControlCommands._();
|
||||
|
||||
/// 单击指令。坐标 x/y 为相对于屏幕的百分比(0.0 ~ 1.0)。
|
||||
static ControlMessage touch(double x, double y) => ControlMessage(
|
||||
action: Action.TOUCH,
|
||||
x: x,
|
||||
y: y,
|
||||
);
|
||||
|
||||
/// 滑动指令。坐标为相对百分比,duration 为毫秒。
|
||||
static ControlMessage swipe(
|
||||
double x1,
|
||||
double y1,
|
||||
double x2,
|
||||
double y2,
|
||||
int durationMs,
|
||||
) =>
|
||||
ControlMessage(
|
||||
action: Action.SWIPE,
|
||||
x1: x1,
|
||||
y1: y1,
|
||||
x2: x2,
|
||||
y2: y2,
|
||||
duration: Int64(durationMs),
|
||||
);
|
||||
|
||||
/// 按键指令。action: 0=按下, 1=抬起(对应 Android KeyEvent.ACTION_DOWN/UP)。
|
||||
static ControlMessage key(int keyCode, int action) => ControlMessage(
|
||||
action: Action.KEY,
|
||||
keyCode: keyCode,
|
||||
keyAction: action,
|
||||
);
|
||||
|
||||
/// 长按指令。坐标 x/y 为相对于屏幕的百分比(0.0 ~ 1.0)。
|
||||
/// 对应 Android 端 RemoteTouchView.createLongPressCommand。
|
||||
static ControlMessage longPress(double x, double y) => ControlMessage(
|
||||
action: Action.LONG_PRESS,
|
||||
x: x,
|
||||
y: y,
|
||||
);
|
||||
|
||||
/// 原始 MotionEvent 指令,用于实现"实时跟手"。
|
||||
/// action: 0=DOWN, 1=UP, 2=MOVE(对应 Android MotionEvent.ACTION_XXX)。
|
||||
static ControlMessage motionEvent(int action, double x, double y) =>
|
||||
ControlMessage(
|
||||
action: Action.MOTION_EVENT,
|
||||
motionAction: action,
|
||||
x: x,
|
||||
y: y,
|
||||
);
|
||||
|
||||
/// 分辨率切换指令。
|
||||
/// [width] 目标长边/宽度(<=0 表示被控端原生分辨率);
|
||||
/// [height] 目标高度(<=0 时由被控端按屏幕宽高比计算);
|
||||
/// [fps] 目标帧率(<=0 表示沿用当前帧率)。
|
||||
static ControlMessage setResolution(int width, int height, int fps) =>
|
||||
ControlMessage(
|
||||
action: Action.SET_RESOLUTION,
|
||||
width: width,
|
||||
height: height,
|
||||
fps: fps,
|
||||
);
|
||||
|
||||
/// 串流模式切换指令。
|
||||
/// [mode] 为 0=WebRTC 全托管 / 1=自编码(自建 MediaCodec 编解码 + video DataChannel 裸流透传)。
|
||||
static ControlMessage streamMode(int mode) => ControlMessage(
|
||||
action: Action.SET_STREAM_MODE,
|
||||
streamMode: mode,
|
||||
);
|
||||
}
|
||||
51
webrtc_controller_flutter/lib/core/utils/device_utils.dart
Normal file
51
webrtc_controller_flutter/lib/core/utils/device_utils.dart
Normal file
@@ -0,0 +1,51 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:android_id/android_id.dart';
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
/// 设备信息工具类(控制端,非系统签名应用)
|
||||
///
|
||||
/// 与 WebRTCControlled 的 DeviceUtils 对应,但控制端没有系统签名,
|
||||
/// 因此无法稳定获取真实的硬件序列号,这里采用「不要求准确」的兜底方案:
|
||||
/// 1. 优先使用官方插件([DeviceInfoPlugin])提供的 serialNumber;
|
||||
/// 2. 如果 serialNumber 为 unknown,则尝试获取 Android ID;
|
||||
/// 3. 失败则使用 iOS 的 identifierForVendor;
|
||||
/// 4. 再失败则生成随机 UUID。
|
||||
class DeviceUtils {
|
||||
DeviceUtils._();
|
||||
|
||||
/// 获取设备标识(适用于普通应用)。
|
||||
///
|
||||
/// 兼容各平台:Android 优先使用官方序列号,其次使用 Android ID,
|
||||
/// iOS 使用 identifierForVendor,均不可用时回退到随机 UUID。
|
||||
static Future<String> getSerialNumber() async {
|
||||
const uuid = Uuid();
|
||||
try {
|
||||
final deviceInfo = DeviceInfoPlugin();
|
||||
if (Platform.isAndroid) {
|
||||
final androidInfo = await deviceInfo.androidInfo;
|
||||
final serial = androidInfo.serialNumber;
|
||||
if (serial.isNotEmpty && serial.toLowerCase() != 'unknown') {
|
||||
return serial;
|
||||
}
|
||||
|
||||
// 如果 serialNumber 获取失败,尝试获取 Android ID
|
||||
const androidIdPlugin = AndroidId();
|
||||
final androidId = await androidIdPlugin.getId();
|
||||
if (androidId != null && androidId.isNotEmpty) {
|
||||
return androidId;
|
||||
}
|
||||
} else if (Platform.isIOS) {
|
||||
final iosInfo = await deviceInfo.iosInfo;
|
||||
final id = iosInfo.identifierForVendor;
|
||||
if (id != null && id.isNotEmpty) {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
} catch (_) {
|
||||
// 获取失败,走兜底逻辑
|
||||
}
|
||||
return uuid.v4();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user