[ { "level": 1, "title": "概述", "type": "title" }, { "content": "", "type": "text" }, { "level": 1, "title": "生成代码过程之一", "type": "title" }, { "content": "首先是功能梳理,本次需要实现的功能预览图如下", "type": "text" }, { "description": "功能预览", "height": "520px", "previewable": true, "type": "image", "url": "https://cs-blog-1300605857.cos.ap-guangzhou.myqcloud.com/article/250208_github_copilot_generate_android_code/%E7%95%8C%E9%9D%A2%E5%9B%BE1.png" }, { "content": "虽然这里的预览图包含了一些界面,但是其实按照现在的工程其实整个界面的绘制都是由Flutter进行,原生仅仅只需要给Flutter提供平台相关的功能。界面的绘制并不需要原生参与", "type": "text" }, { "content": "这里原生的功能仅仅需要为Flutter提供当前的WiFi状态,包括当前连接的WiFi连接状态、SSID以及BSSID这三个值。整体其实是比较简单的,这里我们要做的只是按照特定的协议提供 MethodChannel 供 Flutter 调用即可", "type": "text" }, { "content": "根据上面的梳理,我们已经明确的所需的内容。参照我自己平时的正常编码过程来说开始写代码前首先需要想清楚的大致可以概括为以下步骤", "type": "text" }, { "content": "1、确定实现的大致方案和流程\n2、目前工程对于此类需求的实现方式(遵循已有的设计规范)\n3、明确出入口参数以及类型\n4、描述实现逻辑\n5、这中间可能出现的问题以及应对策略", "type": "text" }, { "content": "我尝试了以下的这段 Prompt,并且在 IDE 中打开了 RequestLocationMethod.kt 、NativeMethod.kt、SpLocationPermissionSet.kt 这三个文件", "type": "text" }, { "content": "你是一名专业的Android开发者,你已经对本工程了如指掌,并且能严格按照当前的设计规范来进行编码,且会在代码留下丰富的注释来说明代码的目的和注意事项。现在你收到了产品经理的需求,你经过拆解后大致确定了以下的实现方案。\n\n以下是你的实现方案以及注意事项\n1、在 NativeMethods.kt 中定义对应的 method 名称。目前协商确定的名称为 method_121_get_wifi_stat\n2、自行实现 INativeMethods.kt 的接口,注意遵循已有的设计规范。你可以参考 RequestLocationMethod.kt 的实现。记住在必要的地方补充好注释\n3、在这个处理方法中,你不需要解析传入的参数。但是你处理完后必须要返回数据到Flutter中。返回数据的格式为JSON格式的数据,内容分别为:\n 1)参数名 ssid,字符串类型,意为当前连接的WiFi的名称,如果没有则返回空白字符串;\n 2)参数名 bssid,字符串类型,意为当前所连接的WiFi的BSSID,如果没有则返回空白字符串;\n 3)参数名 msg,字符串类型,意为当操作结果的说明或者操作失败的错误原因 ;\n 4)参数名 status,字符串类型,可能得取值为:success,意为获取成功;wifi_disable 意为没有打开WiFi;permission_denided 意为没有赋予权限;permission_denied_setting 意为在应用设置中关闭了这个入口的定位权限;location_service_disable 意为定位服务关闭;wifi_disconnected 意为没有连接上WiFi;error 意为发生了其他错误。\n4、你在method实现流程为:\n 1)检查 WiFI 是否打开,如果没有打开,则返回状态 wifi_disable\n 2)检查 WiFi 是否已经连接上,如果没有连接上,则返回状态 wifi_disconnected\n 3)检查定位服务是否打开,如果没有打开,则返回状态 location_service_disable\n 4)检查是否在应用设置中允许在这个入口定位,你可以通过 SpLocationPermissionSet.getLocationPermission(SpLocationPermissionSet.getAttendanceKeyName()) 来判断是否在应用设置中允许这个入口获取定位信息,如果返回值为1,则代表允许打开,继续流程;否则返回状态 permission_denied_setting\n 4)检查是否赋予定位权限,如果没有赋予定位权限,则需要你去申请定位权限。申请权限的流程为:先调用 DialogFactory.createTopDialog(activity) 创建Dialog实例并【通过实例的 setTitle("") 和 setContent("') 来设置权限申请提示文本,通过实例的 show() 和 dismiss() 方法来显示和隐藏弹窗】。然后通过AndPermission申请定位权限,并等待权限申请结果。如果申请通过,则继续流程;如果申请定位权限被拒绝,则返回状态 permission_denided。在继续之前需要注意关闭先前创建的弹窗\n 5)调用适当的API读取当前连接的WiFi的相关信息。如果读取失败,则返回状态 error\n 6)将读取到的信息返回到Flutter,状态为 success\n5、在实现的过程中,你需要注意一下几点:\n 1)兼容性为要求最低支持Android6.0\n 2)你需要在合适的地方加上注释\n 3)申请权限时你需要\n 4)你需要做好异常判断,切记不能让应用出现崩溃!对于异常的情况,你需要记录详细信息到日志中,需要包含异常信息、异常发生步骤以及前后关键参数这些信息\n 5)你需要在流程关键地方、异常情况下记录日志到本地。记录日志你可以调用这个方法 ConfigInfo.logRelease("【TAG】日志内容") 。其中的 TAG 为当前代码文件的名称\n 6)权限申请说明弹窗的标题为:「考勤打卡」申请获取位置权限;内容为:允许后,你可以选择考勤打卡的WiFi,设置考勤打卡规则。;\n 7)注意不要使用魔法变量,在一些有特定意义的值需要先定义为常量再引用(比如状态值 status 这些的取值等等)\n 8)你需要列出每个文件的改动,不能有遗漏\n以上是你的实现方案以及注意事项\n\n现在请你遵循上述规则,编写你的代码", "type": "text" }, { "content": "最终 Github Copilot 给出的答复为", "type": "text" }, { "description": "Copilot 答复", "height": "520px", "previewable": true, "type": "image", "url": "https://cs-blog-1300605857.cos.ap-guangzhou.myqcloud.com/article/250208_github_copilot_generate_android_code/copilot%20%E7%AD%94%E5%A4%8D%201.png" }, { "content": "整体看下来没什么问题,在这个场景下生成的效果还蛮可以的", "type": "text" }, { "level": 1, "title": "生成代码过程之二", "type": "title" }, { "content": "本次实现的功能图为", "type": "text" }, { "description": "功能预览", "height": "520px", "previewable": true, "type": "image", "url": "https://cs-blog-1300605857.cos.ap-guangzhou.myqcloud.com/article/250208_github_copilot_generate_android_code/%E7%95%8C%E9%9D%A2%E5%9B%BE2.png" }, { "content": "首先是功能梳理,这次的功能包括了UI界面以及UI界面对应的点击事件和联动。考验AI对代码布局的理解,但是也并不复杂,因为已经有现成的样板,只是需要按照依葫芦画瓢生成另一个选项就行", "type": "text" }, { "content": "因此,决定尝试使用更简单的描述,让AI自行去推理理解代码内容并生成我想要的代码,这次使用的 prompt 是", "type": "text" }, { "content": "你是一名专业的Android开发者,你已经对本工程了如指掌,并且能严格按照当前的设计规范来进行编码,且会在代码留下丰富的注释来说明代码的目的和注意事项。现在你收到了产品经理的需求,你现在需要理解产品经理的需求并依照已有设计实现需求的功能。\n\n以下是产品经理的需求:\n1、地理位置选项中增加一个名为“考勤打卡-设置打卡WiFi”的选项,界面布局与上面的五个选项样式保持一致\n2、点击“考勤打卡-设置打卡WiFi”选项时,弹窗显示当前选项的状态。逻辑与其他选项保持一致,弹窗的文案调整为这几个。标题为:考勤打卡-设置打卡WiFi;内容为:允许后,你可以在考勤打卡-设置打卡WiFi界面获取现在的WiFi信息,并设置到考勤打卡规则中。\n以下是产品经理的需求。\n\n以下是沟通后协商一致的信息:\n1、新增的选项本地缓存状态的标志为 "attendance" ,也就是对应代码 SPLocationPermissionSet.kt 中的 getAttendanceKeyName() 这个方法\n以上是沟通后协商一致的信息。\n\n现在请你遵循上述规则,编写你的代码", "type": "text" }, { "content": "最终AI给出的答复是", "type": "text" }, { "description": "AI答复", "height": "520px", "previewable": true, "type": "image", "url": "https://cs-blog-1300605857.cos.ap-guangzhou.myqcloud.com/article/250208_github_copilot_generate_android_code/copilot%20%E7%AD%94%E5%A4%8D%202.png" }, { "content": "把最终结果粘贴到工程中,代码可以无障碍编译运行。没有出现错误", "type": "text" }, { "level": 1, "title": "生成成果体验", "type": "title" }, { "content": "最终结果的嵌入没有障碍(逻辑也不算复杂)按照回答内容加入即可。嵌入后仅仅有两处导包错误(SpLocationPermissionSet、DialogFactory),其余的IDE运行并无错误。导包错误感觉也能接受,毕竟AI也没有项目的结构信息,都是参照 RequestMethod.kt 来实现的。运行结果验证如下图所示", "type": "text" }, { "description": "过程一执行结果", "previewable": false, "type": "image", "url": "https://cs-blog-1300605857.cos.ap-guangzhou.myqcloud.com/article/250208_github_copilot_generate_android_code/%E7%BB%93%E6%9E%9C%E6%B5%8B%E8%AF%952.png" }, { "description": "过程2执行结果 ( 1 )", "height": "520px", "previewable": false, "type": "image", "url": "https://cs-blog-1300605857.cos.ap-guangzhou.myqcloud.com/article/250208_github_copilot_generate_android_code/%E7%BB%93%E6%9E%9C2.png" }, { "description": "过程2执行结果 ( 2 )", "height": "520px", "previewable": false, "type": "image", "url": "https://cs-blog-1300605857.cos.ap-guangzhou.myqcloud.com/article/250208_github_copilot_generate_android_code/%E7%BB%93%E6%9E%9C2-1.png" }, { "content": "Github Copilot 生成出来的结果也有一些点需要注意的", "type": "text" }, { "content": "一是AI生成的代码如果不加以 prompt 干预会生成不少魔法变量,虽然不影响代码运行,但是一旦时间长了或者规模大了容易让维护规模难度加大。因此建议加上 prompt 限制", "type": "text" }, { "content": "二是 Copilot Chat 会实时分析代码,如果改到一半再去调整 prompt 的话,它会根据现有的改到一半的代码去分析生成。因此重新调整prompt前最好先恢复会之前的样子(或者你多次通过prompt调整也可以,看个人习惯。我这里期望是一次得到一个比较完善的结果)", "type": "text" }, { "content": "三是有个相对麻烦的地方,Github Copilot没有知识库那样的概念,导致每次新建会话都不会记住之前会话设置的规则。如果用来生成大段的代码其实不是那么合适。如果在同一个会话进行沟通的话,随着上下文的增加,Copilot似乎会遗忘掉一些前面的规则,导致约到后面生成出来的效果越不理想。", "type": "text" }, { "level": 1, "title": "总结", "type": "title" } ]