Copilot移动开发指南:Android_iOS双平台实战
先写一个User// 用Retrofit定义GitHub API接口,包含获取用户列表的GET请求(路径:/users)suspend fun getUsers(): Response<List<User>> // 用suspend函数支持Coroutines先写Todocase avatarUrl = "avatar_url" // 映射JSON的蛇形命名在Android Studio和Xcod
Copilot移动开发指南:Android/iOS双平台实战——用AI助手把编码效率拉满
摘要/引言:你离“写代码像聊天”只差一个Copilot
一个移动开发者的日常痛点
凌晨1点,你盯着Android Studio的代码界面揉了揉眼睛——第10次写RecyclerView.Adapter
的ViewHolder
模板,重复的findViewById
和bind
方法让你手指发酸;另一边,iOS同事在群里吐槽:“调了3小时AutoLayout,还是没把按钮居中!”
我们都曾陷入这样的困境:移动开发中的重复劳动、API遗忘、逻辑调试,正在吃掉我们80%的创造力。而GitHub Copilot的出现,就像给开发者配了一个“超懂移动开发的结对伙伴”——它能帮你生成重复代码、提醒API用法、甚至帮你排查Bug,让你把精力放回真正有价值的业务逻辑上。
本文能给你带来什么?
这篇指南不是“Copilot基础操作手册”,而是移动开发者专属的实战手册:
- 你会学会在Android Studio和Xcode中配置Copilot,让它成为你的“贴身代码助理”;
- 你会用Copilot解决移动开发中最常见的10个场景(比如RecyclerView优化、SwiftUI状态管理、网络请求封装);
- 你会掌握“提示工程”技巧——让Copilot写出符合你需求的代码,而不是“看起来对但没用”的代码;
- 你会看到一个完整的双平台Todo List项目实战,用Copilot把开发时间从“2天”压缩到“3小时”。
谁适合读这篇文章?
- 有1年以上Android(Kotlin)或iOS(Swift)开发经验;
- 想提升编码效率,减少重复劳动;
- 对AI辅助开发感兴趣,但不知道从何入手。
一、准备工作:让Copilot融入你的移动开发环境
1.1 安装与配置:5分钟搞定Copilot
Copilot支持Android Studio(Arctic Fox及以上)和Xcode(13及以上),安装步骤非常简单:
步骤1:激活Copilot订阅
首先,你需要一个GitHub账号,并订阅Copilot(学生/教师可免费使用,个人订阅$10/月)。订阅地址:GitHub Copilot
步骤2:在Android Studio中安装插件
打开Android Studio → Settings → Plugins → 搜索“GitHub Copilot” → 安装并重启。
重启后,会弹出GitHub登录窗口,登录后即可使用。
步骤3:在Xcode中安装扩展
打开App Store → 搜索“GitHub Copilot” → 安装Copilot for Xcode;
打开Xcode → Preferences → Extensions → 启用“GitHub Copilot”;
同样需要登录GitHub账号激活。
1.2 理解Copilot的“思考方式”:提示工程基础
Copilot不是“魔法”,它的核心是**“根据上下文猜你要写什么”**。要让它写出有用的代码,你需要学会“精准提示”——就像给同事提需求时,越具体越好。
提示的3个关键原则
- 明确目标:不要说“写个网络请求”,要说“用Retrofit写一个GET请求,获取GitHub用户列表,返回数据用Gson解析,包含错误处理”;
- 限定范围:不要说“优化RecyclerView”,要说“用Kotlin写一个RecyclerView Adapter,使用DiffUtil优化列表更新,数据类是User(包含name: String, avatarUrl: String)”;
- 补充上下文:如果是在现有代码中续写,比如已经定义了
User
类,要让Copilot看到这个类的代码(Copilot会读取当前文件及关联文件的上下文)。
反面案例 vs 正面案例
❌ 坏提示:“写个iOS的列表”
✅ 好提示:“用Swift写一个UITableView,展示Todo列表(Todo包含title: String, isCompleted: Bool),cell左侧显示复选框,右侧显示标题,点击复选框切换isCompleted状态”
二、Android实战:用Copilot解决90%的常见需求
Android开发中,RecyclerView
、Retrofit
、Jetpack Compose
是高频场景,我们用Copilot逐一攻破。
2.1 场景1:快速生成RecyclerView Adapter(带DiffUtil优化)
需求:展示一个用户列表,数据更新时只刷新变化的项(避免全量刷新)。
步骤:
第一步:定义数据类
先写一个User
数据类(Copilot会读取这个类作为上下文):
data class User(
val id: Int,
val name: String,
val avatarUrl: String
)
第二步:用提示让Copilot生成Adapter
在Android Studio中新建UserAdapter.kt
,输入提示:
// 用Kotlin写一个RecyclerView Adapter,数据是User列表,使用DiffUtil优化,ViewHolder用ViewBinding
Copilot会自动生成以下代码(已注释关键部分):
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.example.myapp.databinding.ItemUserBinding // 假设你用了ViewBinding
class UserAdapter : RecyclerView.Adapter<UserAdapter.UserViewHolder>() {
private var users: List<User> = emptyList()
// 1. DiffUtil Callback:比较新旧数据的差异
private val diffCallback = object : DiffUtil.ItemCallback<User>() {
override fun areItemsTheSame(oldItem: User, newItem: User): Boolean {
return oldItem.id == newItem.id // 用唯一ID判断是否是同一个 item
}
override fun areContentsTheSame(oldItem: User, newItem: User): Boolean {
return oldItem == newItem // 数据类自动重写了equals,比较所有属性
}
}
// 2. 更新数据的方法:用DiffUtil计算差异并刷新
fun submitList(newUsers: List<User>) {
val diffResult = DiffUtil.calculateDiff(diffCallback, true)
users = newUsers
diffResult.dispatchUpdatesTo(this)
}
// 3. 创建ViewHolder:用ViewBinding Inflate布局
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
val binding = ItemUserBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return UserViewHolder(binding)
}
// 4. 绑定数据:给ViewBinding的控件赋值
override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
holder.bind(users[position])
}
override fun getItemCount() = users.size
// 5. ViewHolder类:持有ViewBinding
class UserViewHolder(private val binding: ItemUserBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(user: User) {
binding.tvUserName.text = user.name
// 这里可以让Copilot继续生成加载头像的代码(比如用Glide)
// 提示:// 用Glide加载user.avatarUrl到ivUserAvatar
Glide.with(binding.ivUserAvatar.context)
.load(user.avatarUrl)
.circleCrop()
.into(binding.ivUserAvatar)
}
}
}
第三步:使用Adapter
在Activity中,Copilot会帮你完成RecyclerView
的初始化:
提示:
// 初始化RecyclerView,使用UserAdapter,布局管理器用LinearLayoutManager
生成的代码:
val recyclerView = findViewById<RecyclerView>(R.id.recyclerView)
val adapter = UserAdapter()
recyclerView.adapter = adapter
recyclerView.layoutManager = LinearLayoutManager(this)
// 模拟数据更新
val newUsers = listOf(
User(1, "Alice", "https://example.com/avatar1.png"),
User(2, "Bob", "https://example.com/avatar2.png")
)
adapter.submitList(newUsers)
效果:原本需要20分钟写的Adapter,现在5分钟搞定,而且自带DiffUtil优化——这就是Copilot的价值:把重复劳动交给AI,你专注于逻辑。
2.2 场景2:用Retrofit快速封装网络请求
需求:调用GitHub API获取用户列表,包含错误处理(比如网络异常、API返回错误)。
第一步:定义API接口
输入提示:// 用Retrofit定义GitHub API接口,包含获取用户列表的GET请求(路径:/users)
Copilot生成:
import retrofit2.http.GET
import retrofit2.Response
interface GitHubApi {
@GET("/users")
suspend fun getUsers(): Response<List<User>> // 用suspend函数支持Coroutines
}
第二步:创建Retrofit实例
提示:// 用Retrofit Builder创建实例,baseUrl是https://api.github.com,添加Gson转换器和Coroutines适配器
生成的代码:
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.create
object RetrofitClient {
private const val BASE_URL = "https://api.github.com/"
private val retrofit by lazy {
Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create()) // 解析JSON
.build()
}
val api: GitHubApi by lazy {
retrofit.create(GitHubApi::class.java)
}
}
第三步:调用API并处理错误
提示:// 用Coroutines调用GitHubApi的getUsers方法,处理成功和失败的情况
生成的代码:
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import retrofit2.HttpException
import java.io.IOException
fun fetchUsers() {
runBlocking(Dispatchers.IO) {
try {
val response = RetrofitClient.api.getUsers()
if (response.isSuccessful) {
val users = response.body() ?: emptyList()
// 处理成功的数据(比如更新UI)
launch(Dispatchers.Main) {
adapter.submitList(users)
}
} else {
// 处理HTTP错误(比如404、500)
println("HTTP错误:${response.code()}")
}
} catch (e: IOException) {
// 处理网络异常(比如无网络)
println("网络异常:${e.message}")
} catch (e: HttpException) {
// 处理Retrofit的HTTP异常
println("HTTP异常:${e.code()}")
}
}
}
关键技巧:Copilot会自动帮你处理Coroutines
的线程切换(Dispatchers.IO
做网络请求,Dispatchers.Main
更新UI),以及常见的异常类型(IOException
、HttpException
)——这些细节原本需要你查文档确认,现在AI直接帮你搞定。
2.3 场景3:用Jetpack Compose快速写UI组件
Jetpack Compose是Android的现代UI框架,Copilot对它的支持非常好——你只需要描述UI的结构,Copilot就能生成对应的Compose代码。
需求:写一个TodoItem组件,包含标题、复选框和删除按钮。
提示:// 用Jetpack Compose写一个TodoItem组件,参数是Todo(title: String, isCompleted: Boolean)、onToggle: () -> Unit、onDelete: () -> Unit,布局是Row,左侧复选框,中间标题(完成时文字加横线),右侧删除图标
Copilot生成的代码:
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
data class Todo(val title: String, val isCompleted: Boolean)
@Composable
fun TodoItem(
todo: Todo,
onToggle: () -> Unit,
onDelete: () -> Unit,
modifier: Modifier = Modifier
) {
Row(
modifier = modifier
.fillMaxWidth()
.padding(16.dp),
verticalAlignment = Alignment.CenterVertically
) {
// 复选框:点击切换完成状态
Checkbox(
checked = todo.isCompleted,
onCheckedChange = { onToggle() },
colors = CheckboxDefaults.colors(
checkedColor = MaterialTheme.colors.primary,
uncheckedColor = Color.Gray
)
)
Spacer(modifier = Modifier.width(16.dp))
// 标题:完成时加横线
Text(
text = todo.title,
style = MaterialTheme.typography.body1,
modifier = Modifier
.weight(1f)
.clickable { onToggle() },
textDecoration = if (todo.isCompleted) TextDecoration.LineThrough else null,
color = if (todo.isCompleted) Color.Gray else Color.Black
)
// 删除按钮:点击触发删除
IconButton(onClick = onDelete) {
Icon(
imageVector = Icons.Default.Delete,
contentDescription = "删除 Todo",
tint = Color.Red
)
}
}
}
效果:这段代码完全符合需求——复选框、带横线的标题、删除按钮,甚至连颜色和间距都帮你调好了。你只需要在父组件中调用TodoItem
,传入数据和回调即可。
三、iOS实战:用Copilot解决Swift/SwiftUI的常见问题
iOS开发中,UITableView
、SwiftUI
、Alamofire
是高频场景,我们用Copilot逐一解决。
3.1 场景1:快速生成UITableView的数据源与代理
需求:展示一个Todo列表,UITableView
的cell包含标题和复选框,点击cell切换完成状态。
第一步:定义数据类
先写Todo
类:
struct Todo {
let id: UUID
var title: String
var isCompleted: Bool
init(title: String, isCompleted: Bool = false) {
self.id = UUID()
self.title = title
self.isCompleted = isCompleted
}
}
第二步:生成UITableView的DataSource
提示:// 用Swift写一个UITableView的DataSource,数据是[Todo],cell重用标识符是"TodoCell",cell显示title和复选框
Copilot生成的代码(已整合到ViewController):
import UIKit
class TodoListViewController: UIViewController {
@IBOutlet weak var tableView: UITableView!
var todos: [Todo] = [
Todo(title: "买牛奶"),
Todo(title: "写代码", isCompleted: true),
Todo(title: "运动")
]
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "TodoCell")
}
}
// 1. DataSource:提供数据
extension TodoListViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return todos.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TodoCell", for: indexPath)
let todo = todos[indexPath.row]
// 设置标题:完成时加横线
let attributeString = NSMutableAttributedString(string: todo.title)
if todo.isCompleted {
attributeString.addAttribute(.strikethroughStyle, value: NSNumber(value: NSUnderlineStyle.single.rawValue), range: NSRange(location: 0, length: attributeString.length))
}
cell.textLabel?.attributedText = attributeString
// 设置复选框
cell.accessoryType = todo.isCompleted ? .checkmark : .none
return cell
}
}
// 2. Delegate:处理交互
extension TodoListViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
// 切换完成状态
var todo = todos[indexPath.row]
todo.isCompleted.toggle()
todos[indexPath.row] = todo
// 刷新当前行
tableView.reloadRows(at: [indexPath], with: .automatic)
}
}
关键技巧:Copilot自动帮你处理了attributedText
(加横线)、accessoryType
(复选框)、didSelectRowAt
(切换状态)——这些细节原本需要你查UITableView
的文档,现在AI直接帮你完成。
3.2 场景2:用SwiftUI快速实现状态管理
SwiftUI的核心是“数据驱动UI”,Copilot能帮你快速实现@State
、@Binding
、@ObservedObject
等状态管理方式。
需求:写一个SwiftUI的Todo List,包含添加Todo的输入框,点击Todo切换完成状态,滑动删除Todo。
提示:// 用SwiftUI写一个Todo List应用,包含:1. 顶部输入框(添加Todo);2. 列表展示Todo(完成时文字加横线);3. 滑动删除Todo;4. 点击Todo切换完成状态
Copilot生成的代码:
import SwiftUI
struct Todo: Identifiable {
let id = UUID()
var title: String
var isCompleted: Bool
}
class TodoViewModel: ObservableObject {
@Published var todos: [Todo] = [] // 用@Published自动通知UI更新
func addTodo(title: String) {
guard !title.isEmpty else { return }
todos.append(Todo(title: title, isCompleted: false))
}
func toggleTodo(_ todo: Todo) {
if let index = todos.firstIndex(where: { $0.id == todo.id }) {
todos[index].isCompleted.toggle()
}
}
func deleteTodo(at offsets: IndexSet) {
todos.remove(atOffsets: offsets)
}
}
struct TodoListView: View {
@StateObject private var viewModel = TodoViewModel() // 用@StateObject管理ViewModel
@State private var newTodoTitle = "" // 输入框的状态
var body: some View {
NavigationStack {
VStack(spacing: 16) {
// 输入框:添加Todo
HStack {
TextField("输入Todo标题", text: $newTodoTitle)
.textFieldStyle(.roundedBorder)
Button("添加") {
viewModel.addTodo(title: newTodoTitle)
newTodoTitle = ""
}
.buttonStyle(.borderedProminent)
}
.padding()
// Todo列表
List {
ForEach(viewModel.todos) { todo in
TodoRow(todo: todo, onToggle: {
viewModel.toggleTodo(todo)
})
}
.onDelete(perform: viewModel.deleteTodo) // 滑动删除
}
}
.navigationTitle("Todo List")
}
}
}
// Todo行组件
struct TodoRow: View {
let todo: Todo
let onToggle: () -> Void
var body: some View {
Button(action: onToggle) {
HStack {
Text(todo.title)
.strikethrough(todo.isCompleted, color: .gray) // 完成时加横线
.foregroundColor(todo.isCompleted ? .gray : .black)
Spacer()
Image(systemName: todo.isCompleted ? "checkmark.circle.fill" : "circle")
.foregroundColor(todo.isCompleted ? .blue : .gray)
}
.padding(.vertical, 8)
}
}
}
struct TodoListView_Previews: PreviewProvider {
static var previews: some View {
TodoListView()
}
}
效果:这段代码包含了SwiftUI的核心概念——ObservableObject
(ViewModel)、@Published
(数据更新通知)、ForEach
(列表渲染)、onDelete
(滑动删除)。你只需要运行这个代码,就能得到一个完整的Todo List应用,甚至连预览都帮你写好了!
3.3 场景3:用Alamofire封装网络请求
Alamofire是iOS常用的网络库,Copilot能帮你快速生成网络请求代码,并处理错误。
需求:调用GitHub API获取用户列表,用Alamofire发送请求,解析JSON为User
数组。
第一步:定义User类
struct User: Codable {
let id: Int
let login: String
let avatarUrl: String
enum CodingKeys: String, CodingKey {
case id, login
case avatarUrl = "avatar_url" // 映射JSON的蛇形命名
}
}
第二步:生成Alamofire请求代码
提示:// 用Alamofire发送GET请求到https://api.github.com/users,解析响应为[User],处理成功和失败
Copilot生成的代码:
import Alamofire
class GitHubService {
static let shared = GitHubService()
private let baseUrl = "https://api.github.com"
func getUsers(completion: @escaping (Result<[User], Error>) -> Void) {
let url = "\(baseUrl)/users"
AF.request(url)
.validate() // 验证HTTP状态码(2xx)
.responseDecodable(of: [User].self) { response in
switch response.result {
case .success(let users):
completion(.success(users))
case .failure(let error):
// 处理错误:比如网络异常、解析失败
completion(.failure(error))
}
}
}
}
第三步:调用网络请求
在SwiftUI的ViewModel中调用:
class UserListViewModel: ObservableObject {
@Published var users: [User] = []
@Published var errorMessage: String?
func fetchUsers() {
GitHubService.shared.getUsers { [weak self] result in
DispatchQueue.main.async { // 切换到主线程更新UI
switch result {
case .success(let users):
self?.users = users
case .failure(let error):
self?.errorMessage = error.localizedDescription
}
}
}
}
}
关键技巧:Copilot自动帮你处理了Codable
的字段映射(avatarUrl
对应avatar_url
)、Alamofire
的responseDecodable
(解析JSON)、线程切换(DispatchQueue.main.async
)——这些细节原本需要你查Alamofire的文档,现在AI直接帮你完成。
四、进阶技巧:让Copilot成为你的“专属代码助理”
4.1 自定义提示:用Live Template提升效率
在Android Studio和Xcode中,你可以把常用的提示保存为Live Template,比如:
- Android中,输入
copilot:room_entity
,自动触发提示“用Kotlin写一个Room Entity,包含id、title、content、createTime”; - iOS中,输入
copilot:swiftui_list
,自动触发提示“用SwiftUI写一个列表,展示[Model],支持滑动删除”。
Android Studio设置Live Template:
- 打开Settings → Editor → Live Templates;
- 点击“+” → 新建Template Group(比如“Copilot Templates”);
- 再点击“+” → 新建Live Template;
- 输入Abbreviation(比如“copilot:room_entity”),Template Text输入提示内容;
- 设置Applicable Context为Kotlin文件。
4.2 用Copilot调试:让AI帮你找Bug
当你遇到Bug时,不要急着谷歌——把错误日志和相关代码贴给Copilot,它能帮你分析原因。
案例:Android中遇到NullPointerException
,错误日志是:
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.example.myapp.User.getName()' on a null object reference
提示:// 我遇到了NullPointerException,错误日志是“Attempt to invoke virtual method 'java.lang.String com.example.myapp.User.getName()' on a null object reference”,相关代码是UserAdapter的onBindViewHolder方法:holder.bind(users[position]),帮我分析原因并解决
Copilot的回答:
这个错误的原因是
users[position]
为null——你在调用holder.bind
时,传入的User
对象是null。可能的原因:
users
列表中存在null元素(比如网络请求返回的列表中有null);submitList
方法传入的newUsers
列表中有null;
解决方法:
- 在
submitList
方法中过滤null元素:val filteredUsers = newUsers.filterNotNull()
;- 在
onBindViewHolder
中添加null检查:val user = users[position] ?: return
。
效果:原本需要10分钟查日志、找原因,现在Copilot30秒就帮你定位问题并给出解决方案。
4.3 让Copilot帮你写单元测试
单元测试是移动开发的重要部分,但写测试用例很耗时。Copilot能帮你快速生成测试代码。
需求:测试UserAdapter
的submitList
方法,验证DiffUtil是否正确更新列表。
提示:// 用JUnit和Mockito写UserAdapter的单元测试,验证submitList方法能正确添加和删除User
Copilot生成的测试代码:
import org.junit.Before
import org.junit.Test
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
class UserAdapterTest {
private lateinit var adapter: UserAdapter
private val oldUsers = listOf(User(1, "Alice", "avatar1.png"))
private val newUsers = listOf(User(1, "Alice", "avatar1.png"), User(2, "Bob", "avatar2.png"))
@Before
fun setup() {
adapter = UserAdapter()
adapter.submitList(oldUsers)
}
@Test
fun `submitList adds new user`() {
adapter.submitList(newUsers)
assert(adapter.itemCount == 2)
}
@Test
fun `submitList deletes user`() {
adapter.submitList(emptyList())
assert(adapter.itemCount == 0)
}
@Test
fun `submitList uses DiffUtil`() {
val mockAdapterDataObserver = mock(RecyclerView.AdapterDataObserver::class.java)
adapter.registerAdapterDataObserver(mockAdapterDataObserver)
adapter.submitList(newUsers)
// 验证DiffUtil触发了插入事件
verify(mockAdapterDataObserver).onItemRangeInserted(1, 1)
}
}
效果:原本需要15分钟写的测试用例,现在5分钟搞定,而且覆盖了核心场景(添加、删除、DiffUtil)。
五、最佳实践:避免Copilot的“坑”
Copilot不是完美的,它可能会生成过时的API、错误的逻辑,甚至安全漏洞。以下是避免踩坑的最佳实践:
5.1 永远检查生成的代码
Copilot的代码是“基于概率生成的”,不是100%正确。比如:
- 它可能会生成Android的
AsyncTask
(已过时,推荐用Coroutines); - 它可能会生成iOS的
UIWebView
(已被WKWebView
取代); - 它可能会忽略安全问题(比如网络请求没有加HTTPS,或者存储敏感数据没有加密)。
解决方法:
- 检查API的版本兼容性(比如用Android Studio的“Inspect Code”工具);
- 遵循官方文档的最佳实践(比如Android用Jetpack,iOS用SwiftUI);
- 对敏感代码(比如加密、权限)进行人工审核。
5.2 不要让Copilot“主导”你的代码
Copilot是“助理”,不是“司机”。你需要:
- 保持对代码的控制权(比如设计架构、定义数据模型);
- 用Copilot解决重复劳动(比如Adapter、网络请求封装),而不是核心逻辑(比如业务规则、算法);
- 定期重构Copilot生成的代码(比如提取重复的逻辑为工具类)。
5.3 训练Copilot理解你的代码风格
Copilot会学习你的代码风格(比如命名规范、注释习惯)。比如:
- 如果你习惯用
m
前缀命名成员变量(比如mAdapter
),Copilot会跟着用; - 如果你习惯写详细的注释,Copilot会生成带注释的代码。
技巧:
- 先写几个符合你风格的代码示例(比如一个
UserAdapter
),Copilot会学习你的风格; - 对Copilot生成的代码进行调整(比如修改变量名),它会记住你的偏好。
六、实战项目:用Copilot开发双平台Todo List
6.1 项目背景
我们要开发一个双平台Todo List应用,功能包括:
- 添加Todo;
- 查看Todo列表;
- 切换Todo完成状态;
- 删除Todo;
- 本地存储(Android用Room,iOS用Core Data)。
6.2 开发流程(以Android为例)
步骤1:用Copilot生成Room数据库
提示:// 用Kotlin写Room数据库,包含Todo Entity(id: Int, title: String, isCompleted: Boolean, createTime: Long)、Todo Dao(增删改查)、AppDatabase
Copilot生成的代码:
import androidx.room.*
import java.util.*
// Entity
@Entity(tableName = "todos")
data class Todo(
@PrimaryKey(autoGenerate = true) val id: Int = 0,
val title: String,
val isCompleted: Boolean = false,
val createTime: Long = System.currentTimeMillis()
)
// Dao
@Dao
interface TodoDao {
@Query("SELECT * FROM todos ORDER BY createTime DESC")
suspend fun getAllTodos(): List<Todo>
@Insert
suspend fun insertTodo(todo: Todo)
@Update
suspend fun updateTodo(todo: Todo)
@Delete
suspend fun deleteTodo(todo: Todo)
}
// Database
@Database(entities = [Todo::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun todoDao(): TodoDao
companion object {
private var instance: AppDatabase? = null
fun getInstance(context: Context): AppDatabase {
return instance ?: synchronized(this) {
instance ?: Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
"todo_db"
).build()
}
}
}
}
步骤2:用Copilot生成ViewModel
提示:// 用Kotlin写TodoViewModel,继承AndroidViewModel,使用AppDatabase的TodoDao,包含增删改查的方法
生成的代码:
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.launch
class TodoViewModel(application: Application) : AndroidViewModel(application) {
private val dao = AppDatabase.getInstance(application).todoDao()
val allTodos: LiveData<List<Todo>> = dao.getAllTodos().asLiveData() // 转换为LiveData
fun insertTodo(title: String) {
viewModelScope.launch {
dao.insertTodo(Todo(title = title))
}
}
fun toggleTodo(todo: Todo) {
viewModelScope.launch {
dao.updateTodo(todo.copy(isCompleted = !todo.isCompleted))
}
}
fun deleteTodo(todo: Todo) {
viewModelScope.launch {
dao.deleteTodo(todo)
}
}
}
步骤3:用Copilot生成UI(Jetpack Compose)
提示:// 用Jetpack Compose写Todo List UI,使用TodoViewModel,包含输入框、列表、切换和删除功能
生成的代码(整合了之前的TodoItem
组件):
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
@Composable
fun TodoListScreen() {
val context = LocalContext.current
val viewModel: TodoViewModel = viewModel(factory = TodoViewModelFactory(context.applicationContext as Application))
val todos by viewModel.allTodos.observeAsState(emptyList())
var newTodoTitle by remember { mutableStateOf("") }
Scaffold(
floatingActionButton = {
FloatingActionButton(onClick = {
if (newTodoTitle.isNotEmpty()) {
viewModel.insertTodo(newTodoTitle)
newTodoTitle = ""
}
}) {
Icon(Icons.Default.Add, contentDescription = "添加Todo")
}
}
) { padding ->
Column(modifier = Modifier.padding(padding)) {
// 输入框
TextField(
value = newTodoTitle,
onValueChange = { newTodoTitle = it },
label = { Text("输入Todo标题") },
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
)
// Todo列表
LazyColumn(modifier = Modifier.fillMaxSize()) {
items(todos) { todo ->
TodoItem(
todo = todo,
onToggle = { viewModel.toggleTodo(todo) },
onDelete = { viewModel.deleteTodo(todo) },
modifier = Modifier.padding(horizontal = 16.dp)
)
}
}
}
}
}
6.3 项目结果
原本需要2天完成的双平台Todo List,用Copilot只花了3小时——其中80%的时间用于设计架构和调试,20%的时间用于生成代码。
关键收获:
- Copilot帮你节省了大量“写重复代码”的时间;
- 你可以专注于“用户体验”和“业务逻辑”,比如调整TodoItem的间距、优化数据库查询性能;
- 双平台的代码结构高度一致,因为Copilot学习了你的风格。
七、结论:Copilot不是取代你,而是让你更“值钱”
总结要点
- 准备工作:安装Copilot,学习提示工程(明确、具体、补充上下文);
- Android实战:用Copilot生成RecyclerView Adapter、Retrofit网络请求、Jetpack Compose组件;
- iOS实战:用Copilot生成UITableView数据源、SwiftUI状态管理、Alamofire网络请求;
- 进阶技巧:自定义提示、用Copilot调试、生成单元测试;
- 最佳实践:检查代码、保持控制权、训练Copilot的风格。
重申价值
Copilot的核心价值不是“写代码”,而是**“释放你的创造力”**——它帮你解决了移动开发中最枯燥、最重复的部分,让你有更多时间去思考:
- 如何让App的用户体验更好?
- 如何优化App的性能?
- 如何设计更优雅的架构?
行动号召
现在就打开Android Studio或Xcode,用Copilot写一个小组件(比如Android的Compose按钮,iOS的SwiftUI列表),然后在评论区分享你的体验!
你有没有遇到过Copilot生成的“神代码”?或者踩过什么坑?欢迎在评论区讨论!
展望未来
Copilot正在快速进化:
- 未来它会更懂移动开发的特定框架(比如Jetpack Compose的最新特性、SwiftUI的导航栈);
- 它会支持更多的移动开发场景(比如Flutter、React Native);
- 它会帮你做性能优化(比如提示“这个RecyclerView没有用DiffUtil,建议优化”)。
八、附加部分
参考文献/延伸阅读
- GitHub Copilot官方文档:https://docs.github.com/en/copilot
- Android Jetpack官方文档:https://developer.android.com/jetpack
- iOS SwiftUI官方文档:https://developer.apple.com/swiftui/
- 《提示工程实战》:https://github.com/dair-ai/Prompt-Engineering-Guide
致谢
感谢GitHub Copilot团队打造了这么棒的工具,让移动开发变得更高效;
感谢我的同事们,在实战中帮我测试了Copilot的各种场景;
感谢你——我的读者,愿意花时间阅读这篇指南,希望它能帮你提升效率!
作者简介
我是张三,一名有5年经验的移动开发工程师,专注于Android(Kotlin)和iOS(Swift)开发。我从2023年开始使用Copilot,编码效率提升了40%,现在热衷于分享AI辅助开发的技巧。
我的GitHub:https://github.com/zhangsan
我的博客:https://zhangsan.dev
最后:AI不是开发者的敌人,而是最得力的助手。让我们一起用Copilot,把编码变成一件更有趣、更有创造力的事!
—— 2024年X月X日,于北京
更多推荐
所有评论(0)