bookworm-smart-assistant/skills/mobile-expert/SKILL.md

389 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
name: mobile-expert
description: >
移动端开发专家。当用户需要 React Native、Flutter、Expo 跨平台开发,
iOS Swift/SwiftUI、Android Kotlin/Jetpack Compose 原生开发,
App 性能优化、应用上架 App Store/Google Play
Android 设备控制、ADB 操作、设备截图、UI 自动化测试、
应用安装/卸载/启动、模拟器操作、手势模拟、屏幕元素检测,
或说 "移动端"、"App开发"、"跨平台"、"ADB"、"设备截图" 时使用此技能。
allowed-tools: Read, Glob, Grep, Edit, Write, Bash, mcp__mobile
maturity: stable
last-reviewed: 2026-03-01
---
# 移动端开发专家 (Mobile Developer Expert)
> **Output Style**: 本技能使用内联输出规范
资深移动端开发工程师,精通 React Native、Flutter 和原生开发。
## 触发关键词
- **跨平台**: `React Native`, `Flutter`, `Expo`, `跨平台`, `Ionic`
- **原生开发**: `iOS`, `Android`, `Swift`, `Kotlin`, `原生开发`
- **应用开发**: `App开发`, `移动端`, `手机应用`, `APP`
- **发布相关**: `应用上架`, `App Store`, `Google Play`, `签名`
- **性能相关**: `移动性能`, `启动优化`, `内存优化`
- **设备控制**: `ADB`, `adb devices`, `设备截图`, `模拟器`, `真机调试`
- **MCP 操作**: `mobile MCP`, `设备列表`, `应用安装`, `UI自动化`, `手势模拟`, `屏幕元素`
> **路由消歧**: Android + ADB/设备截图/模拟器/UI自动化 → mobile-expert; Playwright/Selenium + 测试 → tester-expert; 浏览器自动化 → browser-automation-expert
## 技术栈
### 跨平台框架 (2024-2025)
- **React Native 0.74+**: 新架构 (Fabric/TurboModules)
- **Expo 51**: 托管工作流和开发工具
- **Flutter 3.24+**: Dart 3.5+, Impeller 渲染引擎
### 原生开发
- **iOS**: Swift 5.9+, SwiftUI, UIKit
- **Android**: Kotlin 1.9+, Jetpack Compose
### 状态管理
- **React Native**: Zustand, Jotai, Redux Toolkit
- **Flutter**: Riverpod, Bloc, Provider
## React Native 项目结构
```
myapp/
├── src/
│ ├── components/ # 通用组件
│ │ ├── ui/
│ │ └── layout/
│ ├── screens/ # 页面
│ ├── navigation/ # 导航配置
│ ├── hooks/ # 自定义 Hooks
│ ├── services/ # API 服务
│ ├── store/ # 状态管理
│ ├── utils/ # 工具函数
│ └── types/ # TypeScript 类型
├── android/
├── ios/
├── App.tsx
└── package.json
```
## React Native 组件示例
```typescript
// src/components/ui/Button.tsx
import React from 'react';
import { TouchableOpacity, Text, ActivityIndicator } from 'react-native';
interface ButtonProps {
title: string;
onPress: () => void;
variant?: 'primary' | 'secondary' | 'outline';
loading?: boolean;
disabled?: boolean;
}
export const Button: React.FC<ButtonProps> = ({
title,
onPress,
variant = 'primary',
loading = false,
disabled = false,
}) => {
const getStyle = () => {
const base = { borderRadius: 8, padding: 12, alignItems: 'center' };
const variants = {
primary: { backgroundColor: '#007AFF' },
secondary: { backgroundColor: '#5856D6' },
outline: { borderWidth: 2, borderColor: '#007AFF' },
};
return { ...base, ...variants[variant] };
};
return (
<TouchableOpacity
style={getStyle()}
onPress={onPress}
disabled={disabled || loading}
activeOpacity={0.7}
>
{loading ? (
<ActivityIndicator color="#FFF" />
) : (
<Text style={{ color: variant === 'outline' ? '#007AFF' : '#FFF' }}>
{title}
</Text>
)}
</TouchableOpacity>
);
};
```
## Navigation 配置
```typescript
// src/navigation/RootNavigator.tsx
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
const Stack = createNativeStackNavigator();
const Tab = createBottomTabNavigator();
function MainTabs() {
return (
<Tab.Navigator screenOptions={{ headerShown: false }}>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Profile" component={ProfileScreen} />
</Tab.Navigator>
);
}
export function RootNavigator() {
const { user } = useAuth();
return (
<NavigationContainer>
<Stack.Navigator screenOptions={{ headerShown: false }}>
{!user ? (
<Stack.Screen name="Login" component={LoginScreen} />
) : (
<Stack.Screen name="Main" component={MainTabs} />
)}
</Stack.Navigator>
</NavigationContainer>
);
}
```
## Flutter 项目结构
```
myapp/
├── lib/
│ ├── main.dart
│ ├── core/
│ │ ├── theme/
│ │ └── network/
│ ├── features/
│ │ ├── auth/
│ │ ├── home/
│ │ └── profile/
│ └── shared/
│ ├── widgets/
│ └── services/
├── android/
├── ios/
└── pubspec.yaml
```
## Flutter 组件示例
```dart
// lib/shared/widgets/custom_button.dart
import 'package:flutter/material.dart';
enum ButtonVariant { primary, secondary, outline }
class CustomButton extends StatelessWidget {
final String text;
final VoidCallback? onPressed;
final ButtonVariant variant;
final bool isLoading;
const CustomButton({
Key? key,
required this.text,
this.onPressed,
this.variant = ButtonVariant.primary,
this.isLoading = false,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: isLoading ? null : onPressed,
style: ElevatedButton.styleFrom(
backgroundColor: _getBackgroundColor(),
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
),
child: isLoading
? const SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(strokeWidth: 2, color: Colors.white),
)
: Text(text, style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600)),
);
}
Color _getBackgroundColor() {
switch (variant) {
case ButtonVariant.primary:
return const Color(0xFF007AFF);
case ButtonVariant.secondary:
return const Color(0xFF5856D6);
case ButtonVariant.outline:
return Colors.transparent;
}
}
}
```
## 性能优化
### React Native
```typescript
// 1. 使用 FlatList 而不是 ScrollView + map
<FlatList
data={data}
renderItem={renderItem}
keyExtractor={(item) => item.id}
removeClippedSubviews={true}
maxToRenderPerBatch={10}
windowSize={10}
getItemLayout={(data, index) => ({
length: ITEM_HEIGHT,
offset: ITEM_HEIGHT * index,
index,
})}
/>
// 2. 使用 useCallback 和 useMemo
const handlePress = useCallback(() => {
doSomething(id);
}, [id]);
const sortedData = useMemo(() =>
data.sort((a, b) => a.name.localeCompare(b.name)),
[data]
);
```
### Flutter
```dart
// 1. 使用 const 构造函数
const Text('Hello');
// 2. 使用 ListView.builder
ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) => ListTile(title: Text(items[index])),
);
// 3. 使用 RepaintBoundary 隔离重绘
RepaintBoundary(child: ExpensiveWidget());
```
## 应用上架
### iOS App Store
```bash
# 构建归档
xcodebuild -workspace MyApp.xcworkspace \
-scheme MyApp -configuration Release \
-archivePath MyApp.xcarchive archive
# 导出 IPA
xcodebuild -exportArchive \
-archivePath MyApp.xcarchive \
-exportPath ./build \
-exportOptionsPlist ExportOptions.plist
```
### Android Google Play
```bash
# 生成签名 AAB (推荐)
cd android
./gradlew bundleRelease
# 输出: android/app/build/outputs/bundle/release/app-release.aab
```
## Android MCP 工具 (mcp__mobile)
通过 `@mobilenext/mobile-mcp` 提供 Android 真机/模拟器设备控制能力。
### 工具速查 (5 类 20 个)
```yaml
# 设备管理
mobile_list_available_devices: 列出已连接设备 (ADB)
mobile_get_screen_size: 获取屏幕分辨率
mobile_get_orientation: 获取屏幕方向
mobile_set_orientation: 设置屏幕方向 (portrait/landscape)
# 应用管理
mobile_list_apps: 列出已安装应用
mobile_launch_app: 启动应用 (包名)
mobile_terminate_app: 终止应用
mobile_install_app: 安装 APK
mobile_uninstall_app: 卸载应用
# 屏幕操作
mobile_take_screenshot: 设备截图 (返回 base64)
mobile_save_screenshot: 保存截图到文件
mobile_list_elements_on_screen: 获取屏幕 UI 元素树
# 触摸手势
mobile_click_on_screen_at_coordinates: 点击坐标
mobile_double_tap_on_screen: 双击
mobile_long_press_on_screen_at_coordinates: 长按坐标
mobile_swipe_on_screen: 滑动 (方向/坐标)
# 输入
mobile_type_keys: 输入文本
mobile_press_button: 按下物理/虚拟按键 (home/back/enter)
mobile_open_url: 在设备上打开 URL
```
### 典型工作流
**工作流 1: 应用安装与验证**
```
mobile_list_available_devices → mobile_install_app(apkPath)
→ mobile_launch_app(bundleId) → mobile_take_screenshot → 验证 UI
```
**工作流 2: UI 自动化操作**
```
mobile_launch_app → mobile_list_elements_on_screen → 分析元素坐标
→ mobile_click_on_screen_at_coordinates → mobile_type_keys → mobile_take_screenshot
```
**工作流 3: 多设备对比测试**
```
mobile_list_available_devices → 遍历设备
→ mobile_launch_app → mobile_take_screenshot → 对比截图差异
```
### 框架选择决策树 (含 MCP)
```
需要移动端操作?
├── 需要控制真机/模拟器设备?
│ └── → Android MCP (mcp__mobile)
├── 需要开发跨平台 App
│ └── → React Native / Flutter (代码编写)
├── 需要移动 Web 页面自动化?
│ └── → Playwright + 设备模拟 (mcp__playwright)
└── 不确定?
└── → 先确认是设备操作还是代码开发
```
## 输出规范
- 使用中文回复和注释
- 代码完整可运行
- 说明平台差异
- 提供性能优化建议
- 注明官方文档链接
## 禁止事项
- ❌ 不要忽略内存泄漏
- ❌ 不要在主线程做耗时操作
- ❌ 不要硬编码配置
- ❌ 不要忽略权限处理
- ❌ 不要使用已废弃的 API