8.Android_UiAutomator 报告查看
一、Android UiAutomator报告查看
1.错误类型
1)断言错误:就是断言这个用例的成功或者失败(AssrtionFailedError)
2)脚本错误:UiObjectNotFoundException(找不到对象异常)、java异常等
2.报告状态
1)运行状态
2)结果状态
3)运行信息
运行状态 |
结果状态 |
运行信息 |
运行前(1) | OK(0) | 运行前的信息 |
运行完成(-1) | Errors(-1) | 运行中的信息 |
运行完成 (-1) | Failures(-2) | 运行后的信息 |
3.报告示例说明
二、各种状态报告及定位问题
1)断言失败的例子
- 示例代码:
//断言失败报告例子 public void testDemo1() throws UiObjectNotFoundException{ //点击短信查看是否有无会话产生 //当前界面获取短信按钮 UiObject msm=new UiObject(new UiSelector().text("短信")); UiObject None=new UiObject(new UiSelector().text("短信")); //点击短信按钮 msm.clickAndWaitForNewWindow(); assertTrue(!None.exists()); }
- 生成报告内容:
//运行前 INSTRUMENTATION_STATUS: current=1 INSTRUMENTATION_STATUS: id=UiAutomatorTestRunner INSTRUMENTATION_STATUS: class=Jian1.test1 INSTRUMENTATION_STATUS: stream= Jian1.test1: INSTRUMENTATION_STATUS: numtests=1 INSTRUMENTATION_STATUS: test=testDemo1 INSTRUMENTATION_STATUS_CODE: 1 //运行中 INSTRUMENTATION_STATUS: current=1 INSTRUMENTATION_STATUS: id=UiAutomatorTestRunner INSTRUMENTATION_STATUS: class=Jian1.test1 INSTRUMENTATION_STATUS: stream= Failure in testDemo1: junit.framework.AssertionFailedError//报断言错误 at Jian1.test1.testDemo1(test1.java:17)//错误地点Jian/test1/testDemo1/第17行 at java.lang.reflect.Method.invokeNative(Native Method) at com.android.uiautomator.testrunner.UiAutomatorTestRunner.start(UiAutomatorTestRunner.java:160) at com.android.uiautomator.testrunner.UiAutomatorTestRunner.run(UiAutomatorTestRunner.java:96) at com.android.commands.uiautomator.RunTestCommand.run(RunTestCommand.java:91) at com.android.commands.uiautomator.Launcher.main(Launcher.java:83) at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method) at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:235) at dalvik.system.NativeStart.main(Native Method) INSTRUMENTATION_STATUS: numtests=1 INSTRUMENTATION_STATUS: stack=junit.framework.AssertionFailedError at Jian1.test1.testDemo1(test1.java:17) at java.lang.reflect.Method.invokeNative(Native Method) at com.android.uiautomator.testrunner.UiAutomatorTestRunner.start(UiAutomatorTestRunner.java:160) at com.android.uiautomator.testrunner.UiAutomatorTestRunner.run(UiAutomatorTestRunner.java:96) at com.android.commands.uiautomator.RunTestCommand.run(RunTestCommand.java:91) at com.android.commands.uiautomator.Launcher.main(Launcher.java:83) at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method) at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:235) at dalvik.system.NativeStart.main(Native Method) INSTRUMENTATION_STATUS: test=testDemo1 INSTRUMENTATION_STATUS_CODE: -2 //运行后 INSTRUMENTATION_STATUS: stream= Test results for WatcherResultPrinter=.F Time: 2.577 FAILURES!!! Tests run: 1, Failures: 1, Errors: 0 INSTRUMENTATION_STATUS_CODE: -1
2)报告通过例子
- 示例代码:
//报告通过例子 public void testDemo1() throws UiObjectNotFoundException{ //点击短信查看是否有无会话产生 //当前界面获取短信按钮 UiObject msm=new UiObject(new UiSelector().text("短信")); UiObject None=new UiObject(new UiSelector().text("短信")); //点击短信按钮 msm.clickAndWaitForNewWindow(); // assertTrue(!None.exists()); assertTrue(None.exists()); }
- 生成报告内容:
//运行前 INSTRUMENTATION_STATUS: current=1 INSTRUMENTATION_STATUS: id=UiAutomatorTestRunner INSTRUMENTATION_STATUS: class=Jian1.test1 INSTRUMENTATION_STATUS: stream= Jian1.test1: INSTRUMENTATION_STATUS: numtests=1 INSTRUMENTATION_STATUS: test=testDemo1 INSTRUMENTATION_STATUS_CODE: 1 //运行中 INSTRUMENTATION_STATUS: current=1 INSTRUMENTATION_STATUS: id=UiAutomatorTestRunner INSTRUMENTATION_STATUS: class=Jian1.test1 INSTRUMENTATION_STATUS: stream=. INSTRUMENTATION_STATUS: numtests=1 INSTRUMENTATION_STATUS: test=testDemo1 INSTRUMENTATION_STATUS_CODE: 0 //运行后 INSTRUMENTATION_STATUS: stream= Test results for WatcherResultPrinter=. Time: 3.668 OK (1 test) INSTRUMENTATION_STATUS_CODE: -1
3)脚本错误中途中断例子
- 示例代码:
//脚本错误中断例子 public void testDemo1() throws UiObjectNotFoundException{ //获取一个搜索不到的对象 UiObject msm=new UiObject(new UiSelector().text("短信123")); //点击对象 msm.clickAndWaitForNewWindow(); }
- 生成报告内容:
//运行前 INSTRUMENTATION_STATUS: current=1 INSTRUMENTATION_STATUS: id=UiAutomatorTestRunner INSTRUMENTATION_STATUS: class=Jian1.test1 INSTRUMENTATION_STATUS: stream= Jian1.test1: INSTRUMENTATION_STATUS: numtests=1 INSTRUMENTATION_STATUS: test=testDemo1 INSTRUMENTATION_STATUS_CODE: 1 //运行中 INSTRUMENTATION_STATUS: current=1 INSTRUMENTATION_STATUS: id=UiAutomatorTestRunner INSTRUMENTATION_STATUS: class=Jian1.test1 INSTRUMENTATION_STATUS: stream= Error in testDemo1://脚本运行错误 com.android.uiautomator.core.UiObjectNotFoundException: UiSelector[TEXT=短信123]//找不到对象出现的错误 at com.android.uiautomator.core.UiObject.clickAndWaitForNewWindow(UiObject.java:432) at com.android.uiautomator.core.UiObject.clickAndWaitForNewWindow(UiObject.java:410) at Jian1.test1.testDemo1(test1.java:14)//出现的位置 at java.lang.reflect.Method.invokeNative(Native Method) at com.android.uiautomator.testrunner.UiAutomatorTestRunner.start(UiAutomatorTestRunner.java:160) at com.android.uiautomator.testrunner.UiAutomatorTestRunner.run(UiAutomatorTestRunner.java:96) at com.android.commands.uiautomator.RunTestCommand.run(RunTestCommand.java:91) at com.android.commands.uiautomator.Launcher.main(Launcher.java:83) at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method) at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:235) at dalvik.system.NativeStart.main(Native Method) INSTRUMENTATION_STATUS: numtests=1 INSTRUMENTATION_STATUS: stack=com.android.uiautomator.core.UiObjectNotFoundException: UiSelector[TEXT=短信123] at com.android.uiautomator.core.UiObject.clickAndWaitForNewWindow(UiObject.java:432) at com.android.uiautomator.core.UiObject.clickAndWaitForNewWindow(UiObject.java:410) at Jian1.test1.testDemo1(test1.java:14) at java.lang.reflect.Method.invokeNative(Native Method) at com.android.uiautomator.testrunner.UiAutomatorTestRunner.start(UiAutomatorTestRunner.java:160) at com.android.uiautomator.testrunner.UiAutomatorTestRunner.run(UiAutomatorTestRunner.java:96) at com.android.commands.uiautomator.RunTestCommand.run(RunTestCommand.java:91) at com.android.commands.uiautomator.Launcher.main(Launcher.java:83) at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method) at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:235) at dalvik.system.NativeStart.main(Native Method) INSTRUMENTATION_STATUS: test=testDemo1 INSTRUMENTATION_STATUS_CODE: -1 //运行后 INSTRUMENTATION_STATUS: stream= Test results for WatcherResultPrinter=.E Time: 11.655 FAILURES!!! Tests run: 1, Failures: 0, Errors: 1//一个报错 INSTRUMENTATION_STATUS_CODE: -1
4)多用例同时运行例子
- 示例代码:
public void testDemo1() throws UiObjectNotFoundException{ //获取一个搜索不到的对象 UiObject msm=new UiObject(new UiSelector().text("短信123")); //点击对象 msm.clickAndWaitForNewWindow(); } public void testDemo2(){ UiDevice.getInstance().pressBack(); } public void testDemo3(){ UiDevice.getInstance().pressBack(); assertTrue(false);//断言失败的例子 } public void testDemo4(){ UiDevice.getInstance().pressBack(); } //报告通过例子 public void testDemo5() throws UiObjectNotFoundException{ //点击短信查看是否有无会话产生 //当前界面获取短信按钮 UiObject msm=new UiObject(new UiSelector().text("短信")); UiObject None=new UiObject(new UiSelector().text("短信")); //点击短信按钮 msm.clickAndWaitForNewWindow(); assertTrue(None.exists());//断言成功 }
- 生成报告:
INSTRUMENTATION_STATUS: current=1 INSTRUMENTATION_STATUS: id=UiAutomatorTestRunner INSTRUMENTATION_STATUS: class=Jian1.test1 INSTRUMENTATION_STATUS: stream= Jian1.test1: INSTRUMENTATION_STATUS: numtests=5 INSTRUMENTATION_STATUS: test=testDemo1 INSTRUMENTATION_STATUS_CODE: 1 INSTRUMENTATION_STATUS: current=1 INSTRUMENTATION_STATUS: id=UiAutomatorTestRunner INSTRUMENTATION_STATUS: class=Jian1.test1 INSTRUMENTATION_STATUS: stream= Error in testDemo1: com.android.uiautomator.core.UiObjectNotFoundException: UiSelector[TEXT=短信123] at com.android.uiautomator.core.UiObject.clickAndWaitForNewWindow(UiObject.java:432) at com.android.uiautomator.core.UiObject.clickAndWaitForNewWindow(UiObject.java:410) at Jian1.test1.testDemo1(test1.java:16) at java.lang.reflect.Method.invokeNative(Native Method) at com.android.uiautomator.testrunner.UiAutomatorTestRunner.start(UiAutomatorTestRunner.java:160) at com.android.uiautomator.testrunner.UiAutomatorTestRunner.run(UiAutomatorTestRunner.java:96) at com.android.commands.uiautomator.RunTestCommand.run(RunTestCommand.java:91) at com.android.commands.uiautomator.Launcher.main(Launcher.java:83) at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method) at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:235) at dalvik.system.NativeStart.main(Native Method) INSTRUMENTATION_STATUS: numtests=5 INSTRUMENTATION_STATUS: stack=com.android.uiautomator.core.UiObjectNotFoundException: UiSelector[TEXT=短信123] at com.android.uiautomator.core.UiObject.clickAndWaitForNewWindow(UiObject.java:432) at com.android.uiautomator.core.UiObject.clickAndWaitForNewWindow(UiObject.java:410) at Jian1.test1.testDemo1(test1.java:16) at java.lang.reflect.Method.invokeNative(Native Method) at com.android.uiautomator.testrunner.UiAutomatorTestRunner.start(UiAutomatorTestRunner.java:160) at com.android.uiautomator.testrunner.UiAutomatorTestRunner.run(UiAutomatorTestRunner.java:96) at com.android.commands.uiautomator.RunTestCommand.run(RunTestCommand.java:91) at com.android.commands.uiautomator.Launcher.main(Launcher.java:83) at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method) at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:235) at dalvik.system.NativeStart.main(Native Method) INSTRUMENTATION_STATUS: test=testDemo1 INSTRUMENTATION_STATUS_CODE: -1 INSTRUMENTATION_STATUS: current=2 INSTRUMENTATION_STATUS: id=UiAutomatorTestRunner INSTRUMENTATION_STATUS: class=Jian1.test1 INSTRUMENTATION_STATUS: stream= INSTRUMENTATION_STATUS: numtests=5 INSTRUMENTATION_STATUS: test=testDemo2 INSTRUMENTATION_STATUS_CODE: 1 INSTRUMENTATION_STATUS: current=2 INSTRUMENTATION_STATUS: id=UiAutomatorTestRunner INSTRUMENTATION_STATUS: class=Jian1.test1 INSTRUMENTATION_STATUS: stream=. INSTRUMENTATION_STATUS: numtests=5 INSTRUMENTATION_STATUS: test=testDemo2 INSTRUMENTATION_STATUS_CODE: 0 INSTRUMENTATION_STATUS: current=3 INSTRUMENTATION_STATUS: id=UiAutomatorTestRunner INSTRUMENTATION_STATUS: class=Jian1.test1 INSTRUMENTATION_STATUS: stream= INSTRUMENTATION_STATUS: numtests=5 INSTRUMENTATION_STATUS: test=testDemo3 INSTRUMENTATION_STATUS_CODE: 1 INSTRUMENTATION_STATUS: current=3 INSTRUMENTATION_STATUS: id=UiAutomatorTestRunner INSTRUMENTATION_STATUS: class=Jian1.test1 INSTRUMENTATION_STATUS: stream= Failure in testDemo3: junit.framework.AssertionFailedError at Jian1.test1.testDemo3(test1.java:23) at java.lang.reflect.Method.invokeNative(Native Method) at com.android.uiautomator.testrunner.UiAutomatorTestRunner.start(UiAutomatorTestRunner.java:160) at com.android.uiautomator.testrunner.UiAutomatorTestRunner.run(UiAutomatorTestRunner.java:96) at com.android.commands.uiautomator.RunTestCommand.run(RunTestCommand.java:91) at com.android.commands.uiautomator.Launcher.main(Launcher.java:83) at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method) at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:235) at dalvik.system.NativeStart.main(Native Method) INSTRUMENTATION_STATUS: numtests=5 INSTRUMENTATION_STATUS: stack=junit.framework.AssertionFailedError at Jian1.test1.testDemo3(test1.java:23) at java.lang.reflect.Method.invokeNative(Native Method) at com.android.uiautomator.testrunner.UiAutomatorTestRunner.start(UiAutomatorTestRunner.java:160) at com.android.uiautomator.testrunner.UiAutomatorTestRunner.run(UiAutomatorTestRunner.java:96) at com.android.commands.uiautomator.RunTestCommand.run(RunTestCommand.java:91) at com.android.commands.uiautomator.Launcher.main(Launcher.java:83) at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method) at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:235) at dalvik.system.NativeStart.main(Native Method) INSTRUMENTATION_STATUS: test=testDemo3 INSTRUMENTATION_STATUS_CODE: -2 INSTRUMENTATION_STATUS: current=4 INSTRUMENTATION_STATUS: id=UiAutomatorTestRunner INSTRUMENTATION_STATUS: class=Jian1.test1 INSTRUMENTATION_STATUS: stream= INSTRUMENTATION_STATUS: numtests=5 INSTRUMENTATION_STATUS: test=testDemo4 INSTRUMENTATION_STATUS_CODE: 1 INSTRUMENTATION_STATUS: current=4 INSTRUMENTATION_STATUS: id=UiAutomatorTestRunner INSTRUMENTATION_STATUS: class=Jian1.test1 INSTRUMENTATION_STATUS: stream=. INSTRUMENTATION_STATUS: numtests=5 INSTRUMENTATION_STATUS: test=testDemo4 INSTRUMENTATION_STATUS_CODE: 0 INSTRUMENTATION_STATUS: current=5 INSTRUMENTATION_STATUS: id=UiAutomatorTestRunner INSTRUMENTATION_STATUS: class=Jian1.test1 INSTRUMENTATION_STATUS: stream= INSTRUMENTATION_STATUS: numtests=5 INSTRUMENTATION_STATUS: test=testDemo5 INSTRUMENTATION_STATUS_CODE: 1 INSTRUMENTATION_STATUS: current=5 INSTRUMENTATION_STATUS: id=UiAutomatorTestRunner INSTRUMENTATION_STATUS: class=Jian1.test1 INSTRUMENTATION_STATUS: stream=. INSTRUMENTATION_STATUS: numtests=5 INSTRUMENTATION_STATUS: test=testDemo5 INSTRUMENTATION_STATUS_CODE: 0 INSTRUMENTATION_STATUS: stream= Test results for WatcherResultPrinter=.E..F.. Time: 16.215 FAILURES!!! Tests run: 5, Failures: 1, Errors: 1 INSTRUMENTATION_STATUS_CODE: -1
三、输出信息到报告
1.setup与tearDown
1)setup(开始)
2)tearDown(结尾)
2.相关API
1)Bundle
2)getAutomationSupport().sendStatus(int ,Bundle)
- 例如:
//setUp protected void setUp() throws Exception{ super.setUp(); System.out.println("setUp:用例开始执行了---------"); //新建bundle对象 Bundle bundle=new Bundle(); bundle.putString("key1", "value1"); bundle.putString("key2", "value2"); bundle.putString("key3", "value3"); bundle.putString("key4", "value4"); bundle.putString("key5", "value5"); //发送状态,注意不能跟系统状态码一样(0,1,-1),这里我们用10 getAutomationSupport().sendStatus(10, bundle); }
//testCase public void testReport(){ System.out.println("test:用例正在执行中------------"); //新建bundle对象 Bundle bundle=new Bundle(); bundle.putString("key1-", "value1-"); bundle.putString("key2-", "value2-"); bundle.putString("key3-", "value3-"); bundle.putString("key4-", "value4-"); bundle.putString("key5-", "value5-"); //发送状态,注意不能跟系统状态码一样(0,1,-1),这里我们用11 getAutomationSupport().sendStatus(11, bundle); UiDevice.getInstance().pressBack(); }
//tearDown protected void tearDown() throws Exception { // TODO Auto-generated method stub super.tearDown(); System.out.println("tearDown:用例执行完了-----------"); //新建bundle对象 Bundle bundle=new Bundle(); bundle.putString("key1*", "value1*"); bundle.putString("key2*", "value2*"); bundle.putString("key3*", "value3*"); bundle.putString("key4*", "value4*"); bundle.putString("key5*", "value5*"); //发送状态,注意不能跟系统状态码一样(0,1,-1),这里我们用12 getAutomationSupport().sendStatus(12, bundle); }
- 生成报告:
INSTRUMENTATION_STATUS: current=1 INSTRUMENTATION_STATUS: id=UiAutomatorTestRunner INSTRUMENTATION_STATUS: class=Jian1.test1 INSTRUMENTATION_STATUS: stream= Jian1.test1: INSTRUMENTATION_STATUS: numtests=1 INSTRUMENTATION_STATUS: test=testDemo6 INSTRUMENTATION_STATUS_CODE: 1 setUp:用例开始执行了--------- INSTRUMENTATION_STATUS: key4=value4 INSTRUMENTATION_STATUS: key3=value3 INSTRUMENTATION_STATUS: key5=value5 INSTRUMENTATION_STATUS: key2=value2 INSTRUMENTATION_STATUS: key1=value1 INSTRUMENTATION_STATUS_CODE: 10 Set up:用例开始执行... INSTRUMENTATION_STATUS: key4=value4 INSTRUMENTATION_STATUS: key3=value3 INSTRUMENTATION_STATUS: key5=value5 INSTRUMENTATION_STATUS: key2=value2 INSTRUMENTATION_STATUS: key1=value1 INSTRUMENTATION_STATUS_CODE: 10 tearDown:用例执行完了----------- INSTRUMENTATION_STATUS: key4*=value4* INSTRUMENTATION_STATUS: key5*=value5* INSTRUMENTATION_STATUS: key1*=value1* INSTRUMENTATION_STATUS: key2*=value2* INSTRUMENTATION_STATUS: key3*=value3* INSTRUMENTATION_STATUS_CODE: 12 INSTRUMENTATION_STATUS: current=1 INSTRUMENTATION_STATUS: id=UiAutomatorTestRunner INSTRUMENTATION_STATUS: class=Jian1.test1 INSTRUMENTATION_STATUS: stream=. INSTRUMENTATION_STATUS: numtests=1 INSTRUMENTATION_STATUS: test=testDemo6 INSTRUMENTATION_STATUS_CODE: 0 INSTRUMENTATION_STATUS: stream= Test results for WatcherResultPrinter=. Time: 0.083 OK (1 test) INSTRUMENTATION_STATUS_CODE: -1
四、传入参数控制脚本
- 演示范例
1)通过-e传入数据到用例中,如:拨打一个指定电话
public void testDemo7() throws UiObjectNotFoundException{ //初始化动作(按返回键才能万全退出一个应用) UiDevice.getInstance().pressBack(); UiDevice.getInstance().pressBack(); UiDevice.getInstance().pressBack(); UiDevice.getInstance().pressHome();//返回桌面 //获取对象 UiObject call=new UiObject(new UiSelector().text("拨号"));//拨号按钮 UiObject dialpad=new UiObject(new UiSelector().className("android.widget.TableLayout"));//拨号盘 //点击对象 call.clickAndWaitForNewWindow(); dialpad.clickAndWaitForNewWindow(); //传入参数 Bundle b=getParams(); String phone =(String) b.get("phone");//-e key value -e phone 10086 //逻辑判断和输入 for (int i=0;i<phone.length();i++){ String c=phone.charAt(i)+""; UiObject phoneNum=new UiObject(new UiSelector().text(c));//拨号盘 phoneNum.click(); sleep(1200); } }
- 注意事项:
1.Uiautomator不能进行传参的快速调试,可以先run一下,用例push到手机上之后然后使用命令行进行输入,上面的用例运行命令为:
adb shell uiautomator runtest test.jar --nohup -c Jian1.test1#testDemo7 -e phone 10086
2)通过-e出传入整体控制参数控制脚本,如:清理应用数据
public void testDemo8() throws UiObjectNotFoundException { //初始化动作(按返回键才能万全退出一个应用) UiDevice.getInstance().pressBack(); UiDevice.getInstance().pressBack(); UiDevice.getInstance().pressBack(); UiDevice.getInstance().pressHome();//返回桌面 //传入参数 Bundle b=getParams(); String ctrl=(String) b.get("ctrl"); //开始逻辑判定 boolean isClear=Boolean.valueOf(ctrl); if(isClear){ //执行清理步骤 //点菜单按钮 UiDevice.getInstance().pressMenu(); //点管理应用按钮 UiObject manAPP=new UiObject(new UiSelector().text("管理应用")); manAPP.clickAndWaitForNewWindow(); //滚动查找对象并点击 UiScrollable list=new UiScrollable(new UiSelector().resourceId("android:id/list")); UiObject browser=new UiObject(new UiSelector().text("浏览器")); list.scrollIntoView(browser); browser.clickAndWaitForNewWindow(); //点击清除数据按钮 UiObject clear=new UiObject(new UiSelector().text("清除数据")); clear.clickAndWaitForNewWindow(); //点击确定 UiObject OK=new UiObject(new UiSelector().text("确定")); OK.clearTextField(); }else{ //不执行清理 System.out.println("不执行清理-------------"); } //打开浏览器 UiObject browser=new UiObject(new UiSelector().text("浏览器")); browser.clickAndWaitForNewWindow(); }
- 注意事项
1.Uiautomator不能进行传参的快速调试,可以先run一下,用例push到手机上之后然后使用命令行进行输入,上面的用例运行命令为:
adb shell uiautomator runtest test.jar --nohup -c Jian1.test1#testDemo8 -e ctrl false or adb shell uiautomator runtest test.jar --nohup -c Jian1.test1#testDemo8 -e ctrl true
- 本文为博主学习笔记,未经博主允许不得转载
- 本文仅供交流学习,请勿用于非法途径
- 本文仅是个人意见,如有想法,欢迎交流
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步