├── .DS_Store ├── .idea ├── compiler.xml ├── iOSMonkey.iml ├── libraries │ ├── Maven__aopalliance_aopalliance_1_0.xml │ ├── Maven__cglib_cglib_3_2_6.xml │ ├── Maven__com_alibaba_fastjson_1_2_31.xml │ ├── Maven__com_aventstack_extentreports_3_1_5.xml │ ├── Maven__com_beust_jcommander_1_72.xml │ ├── Maven__com_fasterxml_jackson_core_jackson_annotations_2_8_0.xml │ ├── Maven__com_fasterxml_jackson_core_jackson_core_2_9_6.xml │ ├── Maven__com_fasterxml_jackson_core_jackson_databind_2_8_8.xml │ ├── Maven__com_fasterxml_jackson_dataformat_jackson_dataformat_csv_2_8_8.xml │ ├── Maven__com_fasterxml_jackson_dataformat_jackson_dataformat_yaml_2_9_6.xml │ ├── Maven__com_google_code_findbugs_jsr305_1_3_9.xml │ ├── Maven__com_google_code_gson_gson_2_8_4.xml │ ├── Maven__com_google_errorprone_error_prone_annotations_2_1_3.xml │ ├── Maven__com_google_guava_guava_23_6_jre.xml │ ├── Maven__com_google_inject_guice_4_1_0.xml │ ├── Maven__com_google_j2objc_j2objc_annotations_1_1.xml │ ├── Maven__com_relevantcodes_extentreports_2_41_2.xml │ ├── Maven__com_squareup_okhttp3_okhttp_3_9_1.xml │ ├── Maven__com_squareup_okio_okio_1_13_0.xml │ ├── Maven__commons_beanutils_commons_beanutils_1_9_2.xml │ ├── Maven__commons_codec_commons_codec_1_10.xml │ ├── Maven__commons_collections_commons_collections_3_2_1.xml │ ├── Maven__commons_digester_commons_digester_1_8_1.xml │ ├── Maven__commons_io_commons_io_2_6.xml │ ├── Maven__commons_lang_commons_lang_2_4.xml │ ├── Maven__commons_logging_commons_logging_1_2.xml │ ├── Maven__commons_validator_commons_validator_1_6.xml │ ├── Maven__io_appium_java_client_6_0_0.xml │ ├── Maven__io_rest_assured_json_path_3_1_1.xml │ ├── Maven__io_rest_assured_rest_assured_3_1_1.xml │ ├── Maven__io_rest_assured_rest_assured_common_3_1_1.xml │ ├── Maven__io_rest_assured_xml_path_3_1_1.xml │ ├── Maven__javax_activation_activation_1_1.xml │ ├── Maven__javax_inject_javax_inject_1.xml │ ├── Maven__javax_mail_mail_1_4.xml │ ├── Maven__javax_websocket_javax_websocket_api_1_1.xml │ ├── Maven__javax_xml_bind_jaxb_api_2_2_12.xml │ ├── Maven__junit_junit_4_12.xml │ ├── Maven__log4j_log4j_1_2_17.xml │ ├── Maven__net_bytebuddy_byte_buddy_1_8_3.xml │ ├── Maven__net_iharder_base64_2_3_8.xml │ ├── Maven__org_apache_ant_ant_1_9_6.xml │ ├── Maven__org_apache_ant_ant_launcher_1_9_6.xml │ ├── Maven__org_apache_commons_commons_exec_1_3.xml │ ├── Maven__org_apache_commons_commons_lang3_3_7.xml │ ├── Maven__org_apache_httpcomponents_httpclient_4_5_5.xml │ ├── Maven__org_apache_httpcomponents_httpcore_4_4_6.xml │ ├── Maven__org_apache_httpcomponents_httpmime_4_5_2.xml │ ├── Maven__org_apache_velocity_velocity_1_7.xml │ ├── Maven__org_aspectj_aspectjweaver_1_9_1.xml │ ├── Maven__org_ccil_cowan_tagsoup_tagsoup_1_2_1.xml │ ├── Maven__org_checkerframework_checker_compat_qual_2_0_0.xml │ ├── Maven__org_codehaus_groovy_groovy_2_4_12.xml │ ├── Maven__org_codehaus_groovy_groovy_json_2_4_12.xml │ ├── Maven__org_codehaus_groovy_groovy_xml_2_4_12.xml │ ├── Maven__org_codehaus_mojo_animal_sniffer_annotations_1_14.xml │ ├── Maven__org_freemarker_freemarker_2_3_23.xml │ ├── Maven__org_glassfish_grizzly_grizzly_framework_2_3_3.xml │ ├── Maven__org_glassfish_grizzly_grizzly_http_2_3_3.xml │ ├── Maven__org_glassfish_grizzly_grizzly_http_server_2_3_3.xml │ ├── Maven__org_glassfish_grizzly_grizzly_rcm_2_3_3.xml │ ├── Maven__org_glassfish_tyrus_tyrus_client_1_13_1.xml │ ├── Maven__org_glassfish_tyrus_tyrus_container_grizzly_1_2_1.xml │ ├── Maven__org_glassfish_tyrus_tyrus_core_1_13_1.xml │ ├── Maven__org_glassfish_tyrus_tyrus_spi_1_13_1.xml │ ├── Maven__org_hamcrest_hamcrest_core_1_3.xml │ ├── Maven__org_hamcrest_hamcrest_library_1_3.xml │ ├── Maven__org_jsoup_jsoup_1_9_2.xml │ ├── Maven__org_mongodb_bson_3_3_0.xml │ ├── Maven__org_mongodb_mongodb_driver_3_3_0.xml │ ├── Maven__org_mongodb_mongodb_driver_core_3_3_0.xml │ ├── Maven__org_openpnp_opencv_3_2_0_1.xml │ ├── Maven__org_ow2_asm_asm_6_0.xml │ ├── Maven__org_seleniumhq_selenium_selenium_api_3_12_0.xml │ ├── Maven__org_seleniumhq_selenium_selenium_chrome_driver_3_12_0.xml │ ├── Maven__org_seleniumhq_selenium_selenium_edge_driver_3_12_0.xml │ ├── Maven__org_seleniumhq_selenium_selenium_firefox_driver_3_12_0.xml │ ├── Maven__org_seleniumhq_selenium_selenium_ie_driver_3_12_0.xml │ ├── Maven__org_seleniumhq_selenium_selenium_java_3_12_0.xml │ ├── Maven__org_seleniumhq_selenium_selenium_opera_driver_3_12_0.xml │ ├── Maven__org_seleniumhq_selenium_selenium_remote_driver_3_12_0.xml │ ├── Maven__org_seleniumhq_selenium_selenium_safari_driver_3_12_0.xml │ ├── Maven__org_seleniumhq_selenium_selenium_support_3_12_0.xml │ ├── Maven__org_springframework_spring_aop_5_0_5_RELEASE.xml │ ├── Maven__org_springframework_spring_beans_5_0_5_RELEASE.xml │ ├── Maven__org_springframework_spring_context_5_0_5_RELEASE.xml │ ├── Maven__org_springframework_spring_core_5_0_5_RELEASE.xml │ ├── Maven__org_springframework_spring_expression_5_0_5_RELEASE.xml │ ├── Maven__org_springframework_spring_jcl_5_0_5_RELEASE.xml │ ├── Maven__org_testng_testng_7_0_0_beta1.xml │ ├── Maven__org_uncommons_reportng_1_1_5.xml │ ├── Maven__org_xerial_sqlite_jdbc_3_8_11_1.xml │ └── Maven__org_yaml_snakeyaml_1_21.xml ├── misc.xml ├── modules.xml ├── uiDesigner.xml ├── vcs.xml └── workspace.xml ├── META-INF └── MANIFEST.MF ├── README.md ├── config ├── .DS_Store └── config.yaml ├── iOSMonkey.gif ├── logs └── iOSMonkey.log ├── pom.xml ├── src └── main │ ├── java │ ├── Driver │ │ └── DriverServer.java │ ├── Event │ │ ├── CaseEvent.java │ │ ├── FunctionEvent.java │ │ ├── MonkeyBackEvent.java │ │ ├── MonkeyDaemon.java │ │ ├── MonkeyEvent.java │ │ ├── MonkeyHomeKeyEvent.java │ │ ├── MonkeySpecialEvent.java │ │ ├── MonkeySubmitEvent.java │ │ ├── MonkeySwipeEvent.java │ │ ├── MonkeyTapEvent.java │ │ └── MonkeyXpathEvent.java │ ├── MathRandom.java │ ├── Monkey.java │ ├── ScreenShots │ │ ├── ModifyPic.java │ │ └── Screenshot.java │ ├── Test.java │ └── Untils │ │ ├── FileUntils.java │ │ ├── GetPerformance.java │ │ ├── MailConfig.java │ │ ├── MyLogger.java │ │ ├── SearchCrash.java │ │ └── SendMail.java │ └── resources │ └── log4j.properties ├── testcase ├── .DS_Store └── testcase.yaml ├── 性能文件.png └── 执行流程.png /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xinxi1990/iOSMonkey/b92486fee0257b677e59ff7c8a1deca427568e76/.DS_Store -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /.idea/iOSMonkey.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__aopalliance_aopalliance_1_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__cglib_cglib_3_2_6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_alibaba_fastjson_1_2_31.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_aventstack_extentreports_3_1_5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_beust_jcommander_1_72.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_annotations_2_8_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_core_2_9_6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_databind_2_8_8.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_fasterxml_jackson_dataformat_jackson_dataformat_csv_2_8_8.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_fasterxml_jackson_dataformat_jackson_dataformat_yaml_2_9_6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_google_code_findbugs_jsr305_1_3_9.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_google_code_gson_gson_2_8_4.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_google_errorprone_error_prone_annotations_2_1_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_google_guava_guava_23_6_jre.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_google_inject_guice_4_1_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_google_j2objc_j2objc_annotations_1_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_relevantcodes_extentreports_2_41_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_squareup_okhttp3_okhttp_3_9_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_squareup_okio_okio_1_13_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__commons_beanutils_commons_beanutils_1_9_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__commons_codec_commons_codec_1_10.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__commons_collections_commons_collections_3_2_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__commons_digester_commons_digester_1_8_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__commons_io_commons_io_2_6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__commons_lang_commons_lang_2_4.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__commons_logging_commons_logging_1_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__commons_validator_commons_validator_1_6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__io_appium_java_client_6_0_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__io_rest_assured_json_path_3_1_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__io_rest_assured_rest_assured_3_1_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__io_rest_assured_rest_assured_common_3_1_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__io_rest_assured_xml_path_3_1_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__javax_activation_activation_1_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__javax_inject_javax_inject_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__javax_mail_mail_1_4.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__javax_websocket_javax_websocket_api_1_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__javax_xml_bind_jaxb_api_2_2_12.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__junit_junit_4_12.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__log4j_log4j_1_2_17.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__net_bytebuddy_byte_buddy_1_8_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__net_iharder_base64_2_3_8.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_ant_ant_1_9_6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_ant_ant_launcher_1_9_6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_commons_commons_exec_1_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_commons_commons_lang3_3_7.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_httpcomponents_httpclient_4_5_5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_httpcomponents_httpcore_4_4_6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_httpcomponents_httpmime_4_5_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_velocity_velocity_1_7.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_aspectj_aspectjweaver_1_9_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_ccil_cowan_tagsoup_tagsoup_1_2_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_checkerframework_checker_compat_qual_2_0_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_codehaus_groovy_groovy_2_4_12.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_codehaus_groovy_groovy_json_2_4_12.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_codehaus_groovy_groovy_xml_2_4_12.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_codehaus_mojo_animal_sniffer_annotations_1_14.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_freemarker_freemarker_2_3_23.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_glassfish_grizzly_grizzly_framework_2_3_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_glassfish_grizzly_grizzly_http_2_3_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_glassfish_grizzly_grizzly_http_server_2_3_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_glassfish_grizzly_grizzly_rcm_2_3_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_glassfish_tyrus_tyrus_client_1_13_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_glassfish_tyrus_tyrus_container_grizzly_1_2_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_glassfish_tyrus_tyrus_core_1_13_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_glassfish_tyrus_tyrus_spi_1_13_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_hamcrest_hamcrest_core_1_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_hamcrest_hamcrest_library_1_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_jsoup_jsoup_1_9_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_mongodb_bson_3_3_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_mongodb_mongodb_driver_3_3_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_mongodb_mongodb_driver_core_3_3_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_openpnp_opencv_3_2_0_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_ow2_asm_asm_6_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_seleniumhq_selenium_selenium_api_3_12_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_seleniumhq_selenium_selenium_chrome_driver_3_12_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_seleniumhq_selenium_selenium_edge_driver_3_12_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_seleniumhq_selenium_selenium_firefox_driver_3_12_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_seleniumhq_selenium_selenium_ie_driver_3_12_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_seleniumhq_selenium_selenium_java_3_12_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_seleniumhq_selenium_selenium_opera_driver_3_12_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_seleniumhq_selenium_selenium_remote_driver_3_12_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_seleniumhq_selenium_selenium_safari_driver_3_12_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_seleniumhq_selenium_selenium_support_3_12_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_aop_5_0_5_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_beans_5_0_5_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_context_5_0_5_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_core_5_0_5_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_expression_5_0_5_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_jcl_5_0_5_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_testng_testng_7_0_0_beta1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_uncommons_reportng_1_1_5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_xerial_sqlite_jdbc_3_8_11_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_yaml_snakeyaml_1_21.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/uiDesigner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Main-Class: Monkey 3 | 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 简介 2 | 使用Appium框架二次开发iOS端Monkey测试工具 3 | 4 | 目前支持功能: 5 | 6 | 1.基于随机事件:点击、滑动、输入、xpath定位、返回、重启app等事件,根据随机概率随机触发 7 | 8 | 2.支持多设备并发,替换appium端口和wda端口即可 9 | 10 | 3.支持testcase,需要在yaml文件中配置测试用例 11 | 12 | 4.支持步骤截图并生成gif图片 13 | 14 | 5.支持log打印 15 | 16 | 6.支持appium server自启动 17 | 18 | 7.支持守护线程 19 | 20 | 8.支持崩溃查询并且邮件发送 21 | 22 | 9.支持生成性能文件 23 | 24 | # 项目打包 25 | ```aidl 26 | 根目录下: mvn install 27 | 在target目录下生成jar包 28 | ``` 29 | 30 | # 运行命令 31 | ```shell 32 | cd /target 目录下 33 | 34 | 参数说明: 35 | -f: config文件配置地址 36 | 37 | config文件中配置数据: 38 | 39 | UDID: "606EC265-1ED8-454D-AF80-BEB78A417B55" #设备udid 40 | BUNDLEID: "com.iOS.Demo" #app的bundle id 41 | TIMING: "1" #运行时间,单位分钟 42 | PORT: "3460" #appium端口 43 | PROXYPORT: "5680" #WDA端口 44 | NeedScreenshot: "true" #是否截图, true是截图 45 | ScreenshotFolder: "~/iOSMonkey" #截图目录 46 | VERBOSE: "true" # 打印日志 47 | TRACEPATH: "~/iOSMonkey" # 性能文件路径 48 | AppiumLogFolder: "~/iOSMonkey" # appiumlog文件路径 49 | TestCase: "/Users/xinxi/Desktop/iOSMonkey/testcase.yaml" # 测试用例文件,可选项 50 | 51 | java -jar iOSMonkey-1.0.jar -f ~/config.yaml 52 | 53 | 在APP setCapability 添加 wdaLocalPort 8101 8102 54 | 默认的webDriverAgent监听的端口是8000,不冲突就可以并发了 55 | ``` 56 | 57 | # 生成运行步骤gif图 58 | 59 | 安装ffmpeg brew install ffmpeg 60 | 61 | ![image](https://note.youdao.com/yws/public/resource/4fb1771c92bd4c6fc3d11c145ce90c67/xmlnote/WEBRESOURCE7d4053341f063c70b4ad078e79440159/15988) 62 | 63 | # config配置文件 64 | 在代码中config目录下config.yaml 65 | 66 | # 测试app 67 | 在代码中app目录下有测试app,可以根据配置config.yaml运行 68 | 69 | # 如何生产性能文件 70 | 参考: https://appiumpro.com/editions/12 71 | 72 | 73 | # 相关问题 74 | 75 | 1.iOS9.0版本不能xcuitest,需要iOS9.3 76 | 77 | 2.查看模拟崩溃日志路径
78 | ~/Library/Logs/DiagnosticReports 79 | 80 | 81 | -------------------------------------------------------------------------------- /config/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xinxi1990/iOSMonkey/b92486fee0257b677e59ff7c8a1deca427568e76/config/.DS_Store -------------------------------------------------------------------------------- /config/config.yaml: -------------------------------------------------------------------------------- 1 | UDID: "DDAC13B0-786D-4DC7-A920-4BEAF56CD616" 2 | BUNDLEID: "com.iOS.Demo" 3 | TIMING: "1" 4 | PORT: "3460" 5 | PROXYPORT: "5680" 6 | NeedScreenshot: "true" 7 | ScreenshotFolder: "/Users/xinxi/Desktop/iOSMonkey/pic" 8 | VERBOSE: "true" 9 | TRACEPATH: "/Users/xinxi/Desktop/iOSMonkey" 10 | AppiumLogFolder: "/Users/xinxi/Desktop/iOSMonkey" 11 | TestCase: "/Users/xinxi/Desktop/iOSMonkey/testcase.yaml" -------------------------------------------------------------------------------- /iOSMonkey.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xinxi1990/iOSMonkey/b92486fee0257b677e59ff7c8a1deca427568e76/iOSMonkey.gif -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | iOSMonkey 8 | iOSMonkey 9 | 1.0 10 | 11 | 12 | 13 | maven-assembly-plugin 14 | 15 | false 16 | 17 | jar-with-dependencies 18 | 19 | 20 | 21 | Monkey 22 | 23 | 24 | 25 | 26 | 27 | make-assembly 28 | package 29 | 30 | assembly 31 | 32 | 33 | 34 | 35 | 36 | org.apache.maven.plugins 37 | maven-compiler-plugin 38 | 39 | 8 40 | 8 41 | 42 | 43 | 44 | org.apache.maven.plugins 45 | maven-surefire-plugin 46 | 47 | 48 | 49 | 50 | 51 | 2.4 52 | 53 | 54 | 55 | 56 | 57 | io.appium 58 | java-client 59 | 6.0.0 60 | 61 | 62 | org.seleniumhq.selenium 63 | selenium-java 64 | 3.12.0 65 | 66 | 67 | org.testng 68 | testng 69 | 6.14.3 70 | test 71 | 72 | 73 | net.iharder 74 | base64 75 | 2.3.8 76 | 77 | 78 | log4j 79 | log4j 80 | 1.2.17 81 | test 82 | 83 | 84 | junit 85 | junit 86 | 4.12 87 | test 88 | 89 | 90 | org.yaml 91 | snakeyaml 92 | 1.21 93 | 94 | 95 | log4j 96 | log4j 97 | 1.2.17 98 | compile 99 | 100 | 101 | org.uncommons 102 | reportng 103 | 1.1.5 104 | test 105 | 106 | 107 | com.google.inject 108 | guice 109 | 4.1.0 110 | 111 | 112 | com.aventstack 113 | extentreports 114 | 3.1.5 115 | provided 116 | 117 | 118 | com.relevantcodes 119 | extentreports 120 | 2.41.2 121 | 122 | 123 | org.apache.velocity 124 | velocity 125 | 1.7 126 | 127 | 128 | com.alibaba 129 | fastjson 130 | 1.2.31 131 | compile 132 | 133 | 134 | io.rest-assured 135 | rest-assured 136 | 3.1.1 137 | compile 138 | 139 | 140 | javax.mail 141 | mail 142 | 1.4 143 | 144 | 145 | com.fasterxml.jackson.dataformat 146 | jackson-dataformat-yaml 147 | 2.9.6 148 | 149 | 150 | com.fasterxml.jackson.dataformat 151 | jackson-dataformat-csv 152 | 2.8.8 153 | 154 | 155 | org.testng 156 | testng 157 | 7.0.0-beta1 158 | compile 159 | 160 | 161 | 162 | -------------------------------------------------------------------------------- /src/main/java/Driver/DriverServer.java: -------------------------------------------------------------------------------- 1 | package Driver; 2 | 3 | import java.io.*; 4 | import java.net.URL; 5 | 6 | import static Untils.FileUntils.timeDate; 7 | import static Untils.MyLogger.log_info; 8 | 9 | import io.appium.java_client.android.AndroidDriver; 10 | import io.appium.java_client.ios.IOSDriver; 11 | import io.appium.java_client.remote.IOSMobileCapabilityType; 12 | import io.appium.java_client.remote.MobileCapabilityType; 13 | import org.openqa.selenium.remote.DesiredCapabilities; 14 | 15 | /** 16 | * @author xinxi 17 | * 创建appium driver 18 | */ 19 | 20 | public class DriverServer { 21 | 22 | public static IOSDriver iosDriver; 23 | public static AndroidDriver androidDriver; 24 | private static String rootPath = System.getProperty("user.dir"); 25 | private static String AppiumLog = "/" +timeDate() +"_appium.log"; 26 | private static long AppiumWaitTime = 20 * 1000; // Appium Server启动时间 27 | private static int AppiumPort = 4723; 28 | private static String AppiumHost = "127.0.0.1"; 29 | private static int GlobleWaitTime = 30 * 1000; // 设置全局隐示等待 30 | private static String udid; 31 | private static int appiumPort; 32 | private static int wdaPORT; 33 | 34 | public DriverServer(String UDID,int AppiumPort,int WDAPORT) { 35 | udid = UDID; 36 | appiumPort = AppiumPort; 37 | wdaPORT = WDAPORT; 38 | } 39 | 40 | 41 | 42 | 43 | /** 44 | * 组装Appium的capabilities 45 | * return: driver实例 46 | */ 47 | public IOSDriver baseDriver(String BUNDLEID) throws IOException, InterruptedException { 48 | DesiredCapabilities caps=new DesiredCapabilities(); 49 | caps.setCapability("platformName", "ios"); 50 | caps.setCapability("automationName", "xcuitest"); 51 | caps.setCapability("deviceName", "iPhone"); 52 | caps.setCapability("udid", udid); 53 | caps.setCapability("app", BUNDLEID); 54 | //caps.setCapability("newCommandTimeout", 1800); 55 | //caps.setCapability("wdaConnectionTimeout", 1800*1000); 56 | caps.setCapability("wdaLocalPort", Integer.parseInt(String.valueOf(wdaPORT))); 57 | iosDriver = new IOSDriver(new URL(String.format("http://127.0.0.1:%s/wd/hub", appiumPort)),caps); 58 | log_info(String.format("capabilities配置:%s", iosDriver.getCapabilities())); 59 | log_info("app启动!"); 60 | return iosDriver; 61 | } 62 | 63 | 64 | /** 65 | * 组装iOS的capabilities 66 | * return: driver实例 67 | */ 68 | public IOSDriver IOSBaseDriver() throws IOException, InterruptedException { 69 | DesiredCapabilities capabilities = new DesiredCapabilities(); 70 | String url = "http://"+ AppiumHost +":" + appiumPort + "/wd/hub"; 71 | log_info("appium Remote URL:" + url); 72 | capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "iOS"); 73 | capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, "XCUITest"); 74 | capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "iPhone sim"); 75 | //capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "11.2"); 76 | capabilities.setCapability(MobileCapabilityType.UDID, udid); 77 | capabilities.setCapability(MobileCapabilityType.APP, "com.luojilab.LuoJiFM-IOS"); 78 | capabilities.setCapability(MobileCapabilityType.NO_RESET, true); 79 | capabilities.setCapability(MobileCapabilityType.NEW_COMMAND_TIMEOUT, 1800); 80 | capabilities.setCapability(IOSMobileCapabilityType.WDA_CONNECTION_TIMEOUT, 1800*1000); 81 | capabilities.setCapability(IOSMobileCapabilityType.WDA_LOCAL_PORT,Integer.parseInt(String.valueOf(wdaPORT))); 82 | capabilities.setCapability(IOSMobileCapabilityType.AUTO_ACCEPT_ALERTS,true); 83 | //capabilities.setCapability(IOSMobileCapabilityType.START_IWDP, true); 84 | //capabilities.setCapability("autoWebview", true); 85 | //capabilities.setCapability("xcodeOrgId", "7Q6C9D7LVN"); 86 | // capabilities.setCapability("xcodeSigningId", "iPhone Developer"); 87 | iosDriver = new IOSDriver(new URL(url),capabilities); 88 | log_info(String.format("capabilities配置:%s", iosDriver.getCapabilities())); 89 | log_info("app启动!"); 90 | return iosDriver; 91 | } 92 | 93 | /** 94 | * 组装Android的capabilities 95 | * return: driver实例 96 | */ 97 | public AndroidDriver AndroidBaseDriver() throws IOException, InterruptedException { 98 | DesiredCapabilities caps=new DesiredCapabilities(); 99 | DesiredCapabilities capabilities = new DesiredCapabilities(); 100 | capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android"); 101 | capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, udid); 102 | capabilities.setCapability(MobileCapabilityType.UDID, udid); 103 | capabilities.setCapability(MobileCapabilityType.NEW_COMMAND_TIMEOUT, 1800); 104 | capabilities.setCapability("appPackage", "com.luojilab.player"); 105 | //Android 7要用 uiautomator2 106 | //if(getSDKVersion(udid) > 23){ 107 | // capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, "uiautomator2"); 108 | // log.info("Using uiautomator2"); 109 | //} 110 | String url = "http://"+ AppiumHost +":" + appiumPort + "/wd/hub"; 111 | androidDriver = new AndroidDriver(new URL(url),caps); 112 | log_info("appium URL:" + url); 113 | log_info(String.format("capabilities配置:%s", iosDriver.getCapabilities())); 114 | log_info("app启动!"); 115 | return androidDriver; 116 | } 117 | 118 | 119 | 120 | /** 121 | * 启动appium server 122 | */ 123 | public void startAppiumServer(String AppiumLogFolder) throws IOException, InterruptedException { 124 | String startCmd = String.format("appium -a %s -p %s --log %s --relaxed-security",AppiumHost,appiumPort,AppiumLogFolder + AppiumLog); 125 | log_info("appium运行命令:" + startCmd); 126 | Runtime.getRuntime().exec(startCmd); 127 | Thread.sleep(AppiumWaitTime); 128 | } 129 | 130 | 131 | 132 | /** 133 | * 启动前杀死appium server进程 134 | */ 135 | public void killAppiumServer() throws IOException{ 136 | String serachCmd = String.format("lsof -i:%s", appiumPort); 137 | Process p = Runtime.getRuntime().exec(serachCmd); 138 | InputStream is = p.getInputStream(); 139 | BufferedReader reader = new BufferedReader(new InputStreamReader(is)); 140 | String line ; 141 | while ((line = reader.readLine()) != null) { 142 | if (line.contains(String.valueOf("TCP"))){ 143 | String[] tt=line.split("\\s+"); 144 | String killCmd = String.format("kill -9 %s", tt[1]); 145 | log_info(String.format("kill AppiumServer命令:%s", killCmd)); 146 | Runtime.getRuntime().exec(killCmd); 147 | break; 148 | } 149 | } 150 | is.close(); 151 | reader.close(); 152 | p.destroy(); 153 | } 154 | 155 | /** 156 | * 启动前杀死WDA server进程 157 | */ 158 | public void killWDAServer() throws IOException{ 159 | String serachCmd = String.format("lsof -i:%s", wdaPORT); 160 | Process p = Runtime.getRuntime().exec(serachCmd); 161 | InputStream is = p.getInputStream(); 162 | BufferedReader reader = new BufferedReader(new InputStreamReader(is)); 163 | String line ; 164 | while ((line = reader.readLine()) != null) { 165 | if (line.contains(String.valueOf("TCP"))){ 166 | String[] tt=line.split("\\s+"); 167 | String killCmd = String.format("kill -9 %s", tt[1]); 168 | log_info(String.format("kill WDAServer命令:%s", killCmd)); 169 | Runtime.getRuntime().exec(killCmd); 170 | break; 171 | } 172 | } 173 | is.close(); 174 | reader.close(); 175 | p.destroy(); 176 | } 177 | 178 | 179 | 180 | } 181 | -------------------------------------------------------------------------------- /src/main/java/Event/CaseEvent.java: -------------------------------------------------------------------------------- 1 | package Event; 2 | 3 | 4 | import Driver.DriverServer; 5 | import io.appium.java_client.ios.IOSDriver; 6 | import io.appium.java_client.ios.IOSElement; 7 | 8 | import java.io.IOException; 9 | import java.util.ArrayList; 10 | import java.util.HashMap; 11 | import java.util.List; 12 | import java.util.Map; 13 | import static Untils.FileUntils.readYaml; 14 | import static Untils.MyLogger.log_info; 15 | 16 | /** 17 | * @author xinxi 18 | * 根据步骤生成自动化case 19 | */ 20 | 21 | 22 | public class CaseEvent { 23 | 24 | private static String TestCase = "testcase"; 25 | private static String CaseName = "casename"; 26 | private static String Steps = "steps"; 27 | private static String When = "when"; 28 | private static String By = "by"; 29 | private static String Action = "action"; 30 | private static String SleepTime = "sleeptime"; 31 | private static String SendValue; 32 | private static String Method; 33 | private static String ElementValue; 34 | private static List ElementList; 35 | private static IOSDriver iosDriver; 36 | private static IOSElement iosElement; 37 | private static DriverServer driverServer; 38 | public static String projectPath = System.getProperty("user.dir"); 39 | 40 | public CaseEvent(IOSDriver Driver) { 41 | this.iosDriver = Driver; 42 | } 43 | 44 | public static void main(String[] args) throws InterruptedException, IOException { 45 | driverServer = new DriverServer("606EC265-1ED8-454D-AF80-BEB78A417B55",4723,8001); 46 | driverServer.killWDAServer(); 47 | driverServer.killAppiumServer(); 48 | driverServer.startAppiumServer("./"); 49 | iosDriver = driverServer.baseDriver("com.iOS.Demo"); 50 | } 51 | 52 | 53 | public void generateCase(String casePath) throws InterruptedException { 54 | log_info("测试用例文件路径:" + casePath); 55 | Map caseYaml = readYaml(casePath); 56 | generateRule(caseYaml); 57 | } 58 | 59 | 60 | /** 61 | * 递归解析Case.yaml文件 62 | * @param caseYaml 63 | * @throws InterruptedException 64 | */ 65 | private void generateRule(Map caseYaml) throws InterruptedException { 66 | for (Object key : caseYaml.keySet()) { 67 | Object value = caseYaml.get(key); 68 | if (key.toString().startsWith(TestCase)){ 69 | log_info("测试用例:" + key); 70 | generateRule((Map) value); 71 | }else if (key.toString().startsWith(CaseName)){ 72 | log_info("用例名字:" + value); 73 | }else if (key.toString().startsWith(Steps)){ 74 | log_info("用例步骤:" + value); 75 | for (Object action : (ArrayList) (value)) { 76 | acitonGenerate((Map) action); 77 | } 78 | } 79 | } 80 | } 81 | 82 | 83 | /** 84 | * 映射appium操作元素的动作 85 | * @param actionMap 86 | * @throws InterruptedException 87 | */ 88 | private void acitonGenerate(Map actionMap) throws InterruptedException { 89 | for (Object key : actionMap.keySet()) { 90 | Object value = actionMap.get(key); 91 | if (key.toString().startsWith(When)){ 92 | if (!value.toString().equals("")){ 93 | Method = value.toString().split(";")[0]; 94 | ElementValue = value.toString().split(";")[1]; 95 | log_info("检查【" + ElementValue + "】是否存在"); 96 | if (Method.equals("name")){ 97 | ElementList = iosDriver.findElements(org.openqa.selenium.By.name(ElementValue)); 98 | if (ElementList.size() > 0){ 99 | log_info(ElementValue + "存在"); 100 | continue; 101 | }else { 102 | log_info(ElementValue + "不存在,剩余步骤不执行"); 103 | break; 104 | } 105 | }else if (Method.equals("xpath")){ 106 | ElementList = iosDriver.findElements(org.openqa.selenium.By.xpath(ElementValue)); 107 | if (ElementList.size() > 0){ 108 | log_info(ElementValue + "存在"); 109 | continue; 110 | }else { 111 | log_info(ElementValue + "不存在,剩余步骤不执行"); 112 | break; 113 | } 114 | } 115 | }else { 116 | log_info("没有待检查元素"); 117 | } 118 | 119 | }else if (key.toString().startsWith(By)){ 120 | Method = value.toString().split(";")[0]; 121 | ElementValue = value.toString().split(";")[1]; 122 | log_info("定位元素方法:" + Method); 123 | log_info("定位元素值:" + ElementValue); 124 | if (Method.equals("name")){ 125 | iosElement = (IOSElement) iosDriver.findElement(org.openqa.selenium.By.name(ElementValue)); 126 | }else if (Method.equals("xpath")){ 127 | iosElement = (IOSElement) iosDriver.findElement(org.openqa.selenium.By.xpath(ElementValue)); 128 | } 129 | }else if (key.toString().startsWith(Action)){ 130 | log_info("事件动作:" + value); 131 | if (value.toString().startsWith("click")){ 132 | iosElement.click(); 133 | }else if (value.toString().startsWith("sendKeys")){ 134 | SendValue = value.toString().split(";")[1]; 135 | iosElement.clear(); 136 | iosElement.sendKeys(SendValue); 137 | log_info("输入内容:" + SendValue); 138 | } 139 | }else if (key.toString().startsWith(SleepTime)){ 140 | Thread.sleep(Long.parseLong(String.valueOf(value))); 141 | log_info("等待时间:" + value); 142 | } 143 | } 144 | 145 | } 146 | 147 | } 148 | -------------------------------------------------------------------------------- /src/main/java/Event/FunctionEvent.java: -------------------------------------------------------------------------------- 1 | package Event; 2 | 3 | import io.appium.java_client.AppiumDriver; 4 | import io.appium.java_client.TouchAction; 5 | import io.appium.java_client.pagefactory.AppiumFieldDecorator; 6 | import io.appium.java_client.touch.WaitOptions; 7 | import io.appium.java_client.touch.offset.PointOption; 8 | import org.openqa.selenium.By; 9 | import org.openqa.selenium.Dimension; 10 | import org.openqa.selenium.JavascriptExecutor; 11 | import org.openqa.selenium.support.PageFactory; 12 | import org.testng.Assert; 13 | import org.testng.log4testng.Logger; 14 | import java.time.Duration; 15 | import java.util.HashMap; 16 | import static Untils.MyLogger.log_info; 17 | 18 | 19 | /** 20 | * @author xinxi 21 | * appium基本操作封装类 22 | */ 23 | 24 | public abstract class FunctionEvent { 25 | 26 | public final AppiumDriver driver; 27 | public String PageSource; 28 | public Logger logger; 29 | public Boolean is_exist; 30 | private Dimension dimension; 31 | private TouchAction touchAction; 32 | private long sleepTime = 300; 33 | private int MaxScroll = 10; 34 | private int MaxBack = 10; 35 | 36 | public FunctionEvent(AppiumDriver driver) { 37 | this.driver = driver; 38 | PageFactory.initElements(new AppiumFieldDecorator(driver), this); 39 | touchAction = new TouchAction(this.driver); 40 | } 41 | 42 | 43 | /** 44 | * 查询元素是否存在 45 | * return: bool 46 | */ 47 | public Boolean findElementsBy(By by) throws InterruptedException { 48 | sleep(1); 49 | is_exist = false; 50 | if (driver.findElements(by).size() > 0){ 51 | log_info(String.format("查询到元素:%s",by)); 52 | is_exist = true; 53 | }else { 54 | is_exist = false; 55 | } 56 | return is_exist; 57 | } 58 | 59 | 60 | /** 61 | * 页面是否包含某个文案 62 | * return:bool 63 | */ 64 | public Boolean findElements(String text) throws InterruptedException { 65 | this.sleep(1); 66 | is_exist = false; 67 | PageSource = this.driver.getPageSource(); 68 | if (PageSource.contains(text)){ 69 | is_exist = true; 70 | 71 | }else { 72 | is_exist = false; 73 | } 74 | return is_exist; 75 | } 76 | 77 | 78 | /** 79 | * 断言页面包含某个的元素 80 | */ 81 | public void assertContain(String text) throws InterruptedException { 82 | this.sleep(2); 83 | PageSource = this.driver.getPageSource(); 84 | if (PageSource.contains(text)){ 85 | Assert.assertTrue(true); 86 | }else { 87 | Assert.assertFalse(true); 88 | } 89 | } 90 | 91 | 92 | /** 93 | * 断言页面不包含某个的元素 94 | */ 95 | public void assertNotContain(String text){ 96 | PageSource = this.driver.getPageSource(); 97 | if (!PageSource.contains(text)){ 98 | Assert.assertTrue(true); 99 | }else { 100 | Assert.assertFalse(true); 101 | } 102 | 103 | } 104 | 105 | /** 106 | * 断言页面包含element 107 | * by:元素 108 | */ 109 | public void assertContainBy(By by){ 110 | 111 | if (driver.findElements(by).size() > 0){ 112 | Assert.assertTrue(true); 113 | }else { 114 | Assert.assertFalse(true); 115 | } 116 | 117 | } 118 | 119 | 120 | /** 121 | * 断言页面不包含element 122 | * by:元素 123 | */ 124 | public void assertNotContainBy(By by){ 125 | 126 | if (!(driver.findElements(by).size() > 0)){ 127 | Assert.assertTrue(true); 128 | }else { 129 | Assert.assertFalse(true); 130 | } 131 | } 132 | 133 | 134 | /** 135 | * 等待 136 | */ 137 | public void sleep(int time) throws InterruptedException { 138 | Thread.sleep(1000 * time); 139 | } 140 | 141 | /** 142 | * 获取屏幕尺寸 143 | */ 144 | private Dimension getWindowSize(){ 145 | dimension = driver.manage().window().getSize(); 146 | return dimension; 147 | } 148 | 149 | 150 | /** 151 | * 向上滚动 152 | * @ looper 次数 153 | */ 154 | public void scrollUp(int loop) throws InterruptedException { 155 | for (int i = 0; i < loop ; i++) { 156 | touchAction = new TouchAction(this.driver); 157 | touchAction.press(PointOption.point((int) (getWindowSize().width * 0.5),(int) (getWindowSize().height * 0.3))); 158 | touchAction.waitAction(WaitOptions.waitOptions(Duration.ofSeconds(1))); 159 | touchAction.moveTo(PointOption.point((int) (getWindowSize().width * 0.5),(int) (getWindowSize().height * 0.8))); 160 | touchAction.release(); 161 | touchAction.perform(); 162 | log_info("向上滑动!"); 163 | Thread.sleep(sleepTime); 164 | } 165 | } 166 | 167 | /** 168 | * 向上滚动 169 | * @ looper 次数 170 | */ 171 | public void scrollDown(int loop) throws InterruptedException { 172 | for (int i = 0; i < loop ; i++) { 173 | touchAction = new TouchAction(this.driver); 174 | touchAction.press(PointOption.point((int) (getWindowSize().width * 0.5),(int) (getWindowSize().height * 0.8))); 175 | touchAction.waitAction(WaitOptions.waitOptions(Duration.ofSeconds(1))); 176 | touchAction.moveTo(PointOption.point((int) (getWindowSize().width * 0.5),(int) (getWindowSize().height * 0.3))); 177 | touchAction.release(); 178 | touchAction.perform(); 179 | log_info("向下滑动!"); 180 | Thread.sleep(sleepTime); 181 | } 182 | } 183 | 184 | 185 | 186 | /** 187 | * 向下滚动到某个元素 188 | */ 189 | public void scrollDown(String value) throws InterruptedException { 190 | sleep(1); 191 | JavascriptExecutor js = (JavascriptExecutor) driver; 192 | HashMap scrollObject = new HashMap(); 193 | scrollObject.put("direction", "down"); 194 | scrollObject.put("name", value); 195 | js.executeScript("mobile: scroll", scrollObject); 196 | log_info(String.format("向下滑动到元素:%s", value)); 197 | } 198 | 199 | 200 | 201 | /** 202 | * 向上滚动到某个元素 203 | */ 204 | public void scrollUp(String value){ 205 | JavascriptExecutor js = (JavascriptExecutor) driver; 206 | HashMap scrollObject = new HashMap(); 207 | scrollObject.put("direction", "up"); 208 | scrollObject.put("name", value); 209 | js.executeScript("mobile: scroll", scrollObject); 210 | log_info(String.format("向上滑动到元素:%s", value)); 211 | } 212 | 213 | 214 | /** 215 | * 向下滚动到某个元素 216 | */ 217 | public void scrollDownElement(String value) throws InterruptedException { 218 | while (MaxScroll > 0 ){ 219 | if (findElements(value)){ 220 | break; 221 | }else { 222 | scrollDown(1); 223 | MaxScroll --; 224 | } 225 | } 226 | } 227 | 228 | 229 | /** 230 | * 返回键 231 | */ 232 | public void goBack(){ 233 | driver.navigate().back(); 234 | } 235 | 236 | /** 237 | * 循环返回到某个位置 238 | */ 239 | public void loopBack(By by) throws InterruptedException { 240 | while (MaxBack > 0){ 241 | if (findElementsBy(by)){ 242 | break; 243 | }else { 244 | goBack(); 245 | MaxBack --; 246 | } 247 | } 248 | } 249 | 250 | 251 | /** 252 | * 点击引导蒙层 253 | */ 254 | public void tapGurid(int tapCount){ 255 | 256 | 257 | } 258 | 259 | } -------------------------------------------------------------------------------- /src/main/java/Event/MonkeyBackEvent.java: -------------------------------------------------------------------------------- 1 | package Event; 2 | 3 | import io.appium.java_client.ios.IOSDriver; 4 | import static Untils.MyLogger.log_info; 5 | 6 | 7 | /** 8 | * @author xinxi 9 | * Monkey返回事件 10 | */ 11 | 12 | 13 | public class MonkeyBackEvent extends MonkeyEvent { 14 | private IOSDriver driver; 15 | 16 | public MonkeyBackEvent(IOSDriver driver) { 17 | super(MonkeyEvent.EVENT_TYPE_BACK); 18 | this.driver = driver; 19 | } 20 | 21 | 22 | public int injectEvent() throws Exception { 23 | try { 24 | driver.navigate().back(); 25 | log_info("sending Back Event Over!");; 26 | return MonkeyEvent.INJECT_SUCCESS; 27 | }catch (Exception E){ 28 | log_info(this.getClass().getName() + "-" + "injectEvent异常:" + E); 29 | return INJECT_FAIL; 30 | } 31 | } 32 | 33 | } 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/main/java/Event/MonkeyDaemon.java: -------------------------------------------------------------------------------- 1 | package Event; 2 | 3 | import io.appium.java_client.ios.IOSDriver; 4 | import java.io.BufferedReader; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.util.Timer; 8 | import java.util.TimerTask; 9 | 10 | import static Untils.MyLogger.log_info; 11 | 12 | public class MonkeyDaemon extends TimerTask { 13 | 14 | public static int loopTime = 60 * 1000; // 每隔5s执行一次 15 | private static String UDID; 16 | private static String BUNDLEID; 17 | 18 | 19 | public MonkeyDaemon(String UDID, String BUNDLEID) { 20 | this.UDID = UDID; 21 | this.BUNDLEID = BUNDLEID; 22 | } 23 | 24 | @Override 25 | public void run() { 26 | if (UDID.contains("-")) { 27 | log_info("模拟器检查app运行状态!"); 28 | String runcmd = "xcrun simctl spawn booted log stream --level=debug"; 29 | Process pp = null; 30 | try { 31 | pp = Runtime.getRuntime().exec(runcmd); 32 | } catch (IOException e) { 33 | e.printStackTrace(); 34 | } 35 | BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(pp.getInputStream())); 36 | String line; 37 | int lineCount = 0; 38 | String runstring = ""; 39 | try { 40 | while ((line = bufferedReader.readLine()) != null) { 41 | lineCount++; 42 | if (lineCount < 100) { 43 | runstring += line + "\n"; 44 | } else { 45 | break; 46 | } 47 | } 48 | } catch (IOException e) { 49 | e.printStackTrace(); 50 | } finally { 51 | //System.out.println("===" + runstring + "==="); 52 | if (runstring.contains("LuoJiFMIOS")) { 53 | log_info("模拟器app运行中!"); 54 | } else { 55 | log_info("模拟器app不在运行中!"); 56 | try { 57 | Runtime.getRuntime().exec("xcrun simctl launch booted " + BUNDLEID); 58 | log_info("====非测试APP,重新呼起测试APP===="); 59 | } catch (IOException e) { 60 | e.printStackTrace(); 61 | } 62 | } 63 | } 64 | } else { 65 | log_info("真机检查app运行状态!"); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/Event/MonkeyEvent.java: -------------------------------------------------------------------------------- 1 | package Event; 2 | 3 | /** 4 | * abstract class for monkey event 5 | */ 6 | public abstract class MonkeyEvent { 7 | protected int eventType; 8 | public static final int EVENT_TYPE_TAP = 0; 9 | public static final int EVENT_TYPE_SWIPE = 1; 10 | public static final int EVENT_TYPE_LAUNCH = 2; 11 | public static final int EVENT_TYPE_BACK = 3; 12 | public static final int EVENT_TYPE_SUBMIT = 4; 13 | public static final int EVENT_TYPE_CONTENT = 5; 14 | public static final int EVENT_TYPE_HOMEKEY = 6; 15 | 16 | 17 | 18 | public static final int INJECT_SUCCESS = 1; 19 | public static final int INJECT_FAIL = 0; 20 | 21 | 22 | public MonkeyEvent(int type) { 23 | eventType = type; 24 | } 25 | 26 | /** 27 | * @return event type 28 | */ 29 | public int getEventType() { 30 | return eventType; 31 | } 32 | 33 | /** 34 | * @return true if it is safe to throttle after this event, and false otherwise. 35 | */ 36 | public boolean isThrottlable() { 37 | return true; 38 | } 39 | 40 | 41 | /** 42 | * @return INJECT_SUCCESS if it goes through, and INJECT_FAIL if it fails 43 | * in the case of exceptions, return its corresponding error code 44 | */ 45 | public abstract int injectEvent() throws Exception; 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/Event/MonkeyHomeKeyEvent.java: -------------------------------------------------------------------------------- 1 | package Event; 2 | 3 | import static Untils.MyLogger.log_info; 4 | import io.appium.java_client.ios.IOSDriver; 5 | 6 | 7 | /** 8 | * @author xinxi 9 | * Monkey重新启动app事件类 10 | */ 11 | 12 | 13 | public class MonkeyHomeKeyEvent extends MonkeyEvent{ 14 | private String UDID, BUNDLEID; 15 | public static IOSDriver iosDriver; 16 | 17 | public MonkeyHomeKeyEvent(IOSDriver driver) { 18 | super(MonkeyEvent.EVENT_TYPE_HOMEKEY); 19 | this.iosDriver = driver; 20 | } 21 | 22 | public int injectEvent() throws Exception { 23 | log_info("sending HOMEKEY Event."); 24 | iosDriver.closeApp(); 25 | iosDriver.launchApp(); 26 | return MonkeyEvent.INJECT_SUCCESS; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/Event/MonkeySpecialEvent.java: -------------------------------------------------------------------------------- 1 | package Event; 2 | 3 | import io.appium.java_client.ios.IOSDriver; 4 | import org.openqa.selenium.By; 5 | import java.util.ArrayList; 6 | import static Untils.MyLogger.log_info; 7 | 8 | public class MonkeySpecialEvent { 9 | 10 | public static IOSDriver iosDriver; 11 | private ArrayList arrayList; 12 | private By closeLogin = By.id("medal popview dismiss"); 13 | private By sure = By.name("确定"); 14 | private By freeSee = By.name("随便看看"); 15 | private By cancel = By.name("取消"); 16 | 17 | public MonkeySpecialEvent(IOSDriver driver) { 18 | iosDriver = driver; 19 | arrayList = new ArrayList(); 20 | arrayList.add(closeLogin); 21 | arrayList.add(sure); 22 | arrayList.add(sure); 23 | arrayList.add(freeSee); 24 | arrayList.add(cancel); 25 | } 26 | 27 | 28 | /** 29 | * 关闭弹框 30 | */ 31 | public void closeAlert() throws Exception { 32 | try { 33 | for (Object by : arrayList) { 34 | if (iosDriver.findElements((By) by).size() > 0) { 35 | iosDriver.findElement((By) by).click(); 36 | log_info("关闭弹框"); 37 | } 38 | } 39 | } 40 | catch(Exception E){ 41 | log_info(this.getClass().getName() + "-" + "closeAlert:" + E); 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /src/main/java/Event/MonkeySubmitEvent.java: -------------------------------------------------------------------------------- 1 | package Event; 2 | 3 | import io.appium.java_client.TouchAction; 4 | import io.appium.java_client.ios.IOSDriver; 5 | import io.appium.java_client.touch.offset.PointOption; 6 | import static Untils.MyLogger.log_info; 7 | 8 | 9 | 10 | /** 11 | * @author xinxi 12 | * Monkey输入事件类 13 | */ 14 | 15 | public class MonkeySubmitEvent extends MonkeyEvent { 16 | private IOSDriver driver; 17 | private int x, y; 18 | 19 | public MonkeySubmitEvent(IOSDriver driver, int x, int y) { 20 | super(MonkeyEvent.EVENT_TYPE_SUBMIT); 21 | this.x = x; 22 | this.y = y; 23 | this.driver = driver; 24 | } 25 | 26 | public int injectEvent() throws Exception { 27 | try { 28 | log_info("sending Submit Event : Tap->(" + x + ", " + y + ")"); 29 | TouchAction touchAction = new TouchAction(driver); 30 | touchAction.tap(PointOption.point(x, y)).perform(); 31 | log_info("sending Tap Event Over!"); 32 | return MonkeyEvent.INJECT_SUCCESS; 33 | }catch (Exception E){ 34 | log_info(this.getClass().getName() + "-" + "injectEvent异常:" + E); 35 | return INJECT_FAIL; 36 | } 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/Event/MonkeySwipeEvent.java: -------------------------------------------------------------------------------- 1 | package Event; 2 | 3 | import io.appium.java_client.TouchAction; 4 | import io.appium.java_client.ios.IOSDriver; 5 | import io.appium.java_client.touch.WaitOptions; 6 | import io.appium.java_client.touch.offset.PointOption; 7 | import org.openqa.selenium.Dimension; 8 | import java.time.Duration; 9 | import static Untils.MyLogger.log_info; 10 | 11 | 12 | /** 13 | * @author xinxi 14 | * Monkey滑动类 15 | */ 16 | 17 | public class MonkeySwipeEvent extends MonkeyEvent { 18 | private Dimension dimension; 19 | private TouchAction touchAction; 20 | private long sleepTime = 300; 21 | private IOSDriver driver; 22 | private int MaxScroll = 1; 23 | 24 | 25 | public MonkeySwipeEvent(IOSDriver driver) { 26 | super(MonkeyEvent.EVENT_TYPE_SWIPE); 27 | this.driver = driver; 28 | } 29 | 30 | @Override 31 | public int injectEvent() throws Exception { 32 | return 0; 33 | } 34 | 35 | /** 36 | * 向上滚动事件 37 | */ 38 | public int injectEvent_scrollUp() throws Exception { 39 | try { 40 | log_info("sending scrollUp Event!"); 41 | this.scrollUp(MaxScroll); 42 | log_info("sending scrollUp Over!"); 43 | return MonkeyEvent.INJECT_SUCCESS; 44 | }catch (Exception E){ 45 | log_info(this.getClass().getName() + "-" + "injectEvent异常:" + E); 46 | return INJECT_FAIL; 47 | } 48 | } 49 | 50 | 51 | /** 52 | * 向下滚动事件 53 | */ 54 | public int injectEvent_scrollDown() throws Exception { 55 | try { 56 | log_info("sending scrollDown Event!"); 57 | this.scrollDown(MaxScroll); 58 | log_info("sending scrollDown Over!"); 59 | return MonkeyEvent.INJECT_SUCCESS; 60 | }catch (Exception E){ 61 | log_info(this.getClass().getName() + "-" + "injectEvent异常:" + E); 62 | return INJECT_FAIL; 63 | } 64 | } 65 | 66 | 67 | /** 68 | * 获取屏幕尺寸 69 | */ 70 | private Dimension getWindowSize(){ 71 | dimension = driver.manage().window().getSize(); 72 | return dimension; 73 | } 74 | 75 | /** 76 | * 向上滚动 77 | * @ looper 次数 78 | */ 79 | public void scrollUp(int loop) throws InterruptedException { 80 | for (int i = 0; i < loop ; i++) { 81 | touchAction = new TouchAction(this.driver); 82 | touchAction.press(PointOption.point((int) (getWindowSize().width * 0.5),(int) (getWindowSize().height * 0.3))); 83 | touchAction.waitAction(WaitOptions.waitOptions(Duration.ofSeconds(1))); 84 | touchAction.moveTo(PointOption.point((int) (getWindowSize().width * 0.5),(int) (getWindowSize().height * 0.8))); 85 | touchAction.release(); 86 | touchAction.perform(); 87 | log_info("向上滑动!"); 88 | Thread.sleep(sleepTime); 89 | } 90 | } 91 | 92 | 93 | 94 | 95 | /** 96 | * 向上滚动 97 | * @ looper 次数 98 | */ 99 | public void scrollDown(int loop) throws InterruptedException { 100 | for (int i = 0; i < loop ; i++) { 101 | touchAction = new TouchAction(this.driver); 102 | touchAction.press(PointOption.point((int) (getWindowSize().width * 0.5),(int) (getWindowSize().height * 0.8))); 103 | touchAction.waitAction(WaitOptions.waitOptions(Duration.ofSeconds(1))); 104 | touchAction.moveTo(PointOption.point((int) (getWindowSize().width * 0.5),(int) (getWindowSize().height * 0.3))); 105 | touchAction.release(); 106 | touchAction.perform(); 107 | log_info("向下滑动!"); 108 | Thread.sleep(sleepTime); 109 | } 110 | } 111 | 112 | 113 | 114 | } 115 | -------------------------------------------------------------------------------- /src/main/java/Event/MonkeyTapEvent.java: -------------------------------------------------------------------------------- 1 | package Event; 2 | 3 | import io.appium.java_client.TouchAction; 4 | import io.appium.java_client.ios.IOSDriver; 5 | import io.appium.java_client.touch.offset.PointOption; 6 | import static Untils.MyLogger.log_info; 7 | 8 | 9 | /** 10 | * @author xinxi 11 | * Monkey点击事件类 12 | */ 13 | 14 | public class MonkeyTapEvent extends MonkeyEvent{ 15 | private int x, y; 16 | private IOSDriver driver; 17 | 18 | public MonkeyTapEvent(IOSDriver driver, int x, int y) { 19 | super(MonkeyEvent.EVENT_TYPE_TAP); 20 | this.x = x; 21 | this.y = y; 22 | this.driver = driver; 23 | } 24 | 25 | public int injectEvent() throws Exception { 26 | try { 27 | log_info("sending Tap Event : Tap->(" + x + ", " + y + ")"); 28 | TouchAction touchAction = new TouchAction(driver); 29 | touchAction.tap(PointOption.point(x, y)).perform(); 30 | log_info("sending Tap Event Over!"); 31 | return MonkeyEvent.INJECT_SUCCESS; 32 | }catch (Exception E){ 33 | log_info(this.getClass().getName() + "-" + "injectEvent异常:" + E); 34 | return INJECT_FAIL; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/Event/MonkeyXpathEvent.java: -------------------------------------------------------------------------------- 1 | package Event; 2 | 3 | 4 | import io.appium.java_client.ios.IOSDriver; 5 | import io.appium.java_client.ios.IOSElement; 6 | import org.openqa.selenium.By; 7 | import java.util.List; 8 | import java.util.Random; 9 | import static Untils.MyLogger.log_info; 10 | 11 | /** 12 | * @author xinxi 13 | * Monkey Xpath点击事件类 14 | */ 15 | 16 | 17 | public class MonkeyXpathEvent extends MonkeyEvent { 18 | 19 | private IOSDriver driver; 20 | private By xpath1= By.xpath("//*[contains(name(), 'Text') and" + 21 | " @name!='' and string-length(@label)<10]"); 22 | private By xpath2= By.xpath("//*[contains(name(), 'Image') and @name!='']"); 23 | 24 | public MonkeyXpathEvent(IOSDriver driver) { 25 | super(MonkeyEvent.EVENT_TYPE_CONTENT); 26 | this.driver = driver; 27 | } 28 | 29 | 30 | /** 31 | 随机点击文本控件 32 | */ 33 | public int injectEvent_Text() throws Exception { 34 | try { 35 | log_info("sending injectEvent Text!"); 36 | Random ra = new Random(); 37 | List ellist1 = driver.findElements(xpath1); 38 | if (ellist1.size() > 0 ){ 39 | int randomEl1 = ra.nextInt(ellist1.size() + 1); 40 | IOSElement iosElement = (IOSElement) ellist1.get(randomEl1); 41 | iosElement.click(); 42 | log_info(String.format(this.getClass().getName() + "-" + "injectEvent_Text click %s!", randomEl1)); 43 | return MonkeyEvent.INJECT_SUCCESS; 44 | }else { 45 | log_info(this.getClass().getName() + "-" + "injectEvent_Text miss!"); 46 | return MonkeyEvent.INJECT_FAIL; 47 | } 48 | }catch (Exception E){ 49 | log_info(this.getClass().getName() + "-" + "injectEvent异常:" + E); 50 | return MonkeyEvent.INJECT_FAIL; 51 | } 52 | } 53 | 54 | 55 | /** 56 | 随机点击图标控件 57 | */ 58 | public int injectEvent_Image() throws Exception { 59 | try { 60 | log_info("sending injectEvent Image!"); 61 | Random ra = new Random(); 62 | List ellist1 = driver.findElements(xpath2); 63 | if (ellist1.size() > 0 ){ 64 | int randomEl1 = ra.nextInt(ellist1.size() + 1); 65 | IOSElement iosElement = (IOSElement) ellist1.get(randomEl1); 66 | iosElement.click(); 67 | log_info(String.format(this.getClass().getName() + "-" + "injectEvent_Image click %s!", randomEl1)); 68 | return MonkeyEvent.INJECT_SUCCESS; 69 | }else { 70 | log_info(this.getClass().getName() + "-" + "injectEvent_Image miss!"); 71 | return MonkeyEvent.INJECT_FAIL; 72 | } 73 | }catch (Exception E){ 74 | log_info(this.getClass().getName() + "-" + "injectEvent异常:" + E); 75 | return MonkeyEvent.INJECT_FAIL; 76 | } 77 | } 78 | 79 | 80 | @Override 81 | public int injectEvent() throws Exception { 82 | return 0; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/MathRandom.java: -------------------------------------------------------------------------------- 1 | /** 2 | * @author xinxi 3 | * 随机数类 4 | */ 5 | 6 | 7 | public class MathRandom { 8 | 9 | /** 10 | * 0出现的概率为%40 11 | */ 12 | public static double EVENT_TYPE_TAP = 0.55; 13 | /** 14 | * 1出现的概率为%30 15 | */ 16 | public static double EVENT_TYPE_SWIPE = 0.20; 17 | /** 18 | * 2出现的概率为%10 19 | */ 20 | public static double EVENT_TYPE_BACK = 0.15; 21 | 22 | public static double EVENT_TYPE_SUBMIT = 0.05; 23 | 24 | public static double EVENT_TYPE_CONTENT = 0.00; 25 | 26 | public static double EVENT_TYPE_SPECIAL_POINT = 0.04; 27 | 28 | public static double EVENT_TYPE_HOMEKEY = 0.01; 29 | 30 | 31 | 32 | 33 | public int PercentageRandom() { 34 | double randomNumber; 35 | randomNumber = Math.random(); 36 | if (randomNumber >= 0 && randomNumber <= EVENT_TYPE_TAP) { 37 | return 0; 38 | } else if (randomNumber >= EVENT_TYPE_TAP / 100 && randomNumber <= EVENT_TYPE_TAP + EVENT_TYPE_SWIPE) { 39 | return 1; 40 | } else if (randomNumber >= EVENT_TYPE_TAP + EVENT_TYPE_SWIPE 41 | && randomNumber <= EVENT_TYPE_TAP + EVENT_TYPE_SWIPE + EVENT_TYPE_BACK) { 42 | return 2; 43 | } else if (randomNumber >= EVENT_TYPE_TAP + EVENT_TYPE_SWIPE + EVENT_TYPE_BACK 44 | && randomNumber <= EVENT_TYPE_TAP + EVENT_TYPE_SWIPE + EVENT_TYPE_BACK + EVENT_TYPE_SUBMIT) { 45 | return 3; 46 | } else if (randomNumber >= EVENT_TYPE_TAP + EVENT_TYPE_SWIPE + EVENT_TYPE_BACK + EVENT_TYPE_SUBMIT 47 | && randomNumber <= EVENT_TYPE_TAP + EVENT_TYPE_SWIPE + EVENT_TYPE_BACK + EVENT_TYPE_SUBMIT 48 | + EVENT_TYPE_CONTENT) { 49 | return 4; 50 | }else if (randomNumber >= EVENT_TYPE_TAP + EVENT_TYPE_SWIPE + EVENT_TYPE_BACK + EVENT_TYPE_SUBMIT + EVENT_TYPE_CONTENT 51 | && randomNumber <= EVENT_TYPE_TAP + EVENT_TYPE_SWIPE + EVENT_TYPE_BACK + EVENT_TYPE_SUBMIT 52 | + EVENT_TYPE_CONTENT + EVENT_TYPE_SPECIAL_POINT) { 53 | return 5; 54 | }else if (randomNumber >= EVENT_TYPE_TAP + EVENT_TYPE_SWIPE + EVENT_TYPE_BACK + EVENT_TYPE_SUBMIT + EVENT_TYPE_CONTENT 55 | + EVENT_TYPE_SPECIAL_POINT 56 | && randomNumber <= EVENT_TYPE_TAP + EVENT_TYPE_SWIPE + EVENT_TYPE_BACK + EVENT_TYPE_SUBMIT 57 | + EVENT_TYPE_CONTENT + EVENT_TYPE_SPECIAL_POINT + EVENT_TYPE_HOMEKEY) { 58 | return 6; 59 | } 60 | return -1; 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/Monkey.java: -------------------------------------------------------------------------------- 1 | import Driver.DriverServer; 2 | import Event.*; 3 | import Untils.GetPerformance; 4 | import io.appium.java_client.ios.IOSDriver; 5 | import org.apache.commons.io.FileUtils; 6 | import org.apache.log4j.Level; 7 | import org.openqa.selenium.Dimension; 8 | import ScreenShots.Screenshot; 9 | import java.io.File; 10 | import java.io.IOException; 11 | import java.text.DecimalFormat; 12 | import java.text.NumberFormat; 13 | import java.util.*; 14 | import static Event.MonkeyDaemon.loopTime; 15 | import static Untils.FileUntils.createGif; 16 | import static Untils.FileUntils.readYaml; 17 | import static Untils.MyLogger.initLogger; 18 | import static Untils.MyLogger.log_info; 19 | import static Untils.SearchCrash.*; 20 | 21 | 22 | public class Monkey { 23 | 24 | public static IOSDriver iosDriver; 25 | private int width,height, submitX_mim, 26 | submitX_max, submitY_mim, 27 | submitY_max, contentX_min, 28 | contentX_max, contentY_mim, 29 | contentY_max, special_point_x, 30 | special_point_y; 31 | private static boolean needhelp = false; 32 | private static String ConfigPath; 33 | private static String UDID; 34 | private static String BUNDLEID; 35 | private static String NeedScreenshot; 36 | private static String PORT; 37 | private static String PROXYPORT; 38 | private static String VERBOSE; 39 | private static String TRACEPATH; 40 | private static String ScreenshotFolder; 41 | private static String AppiumLogFolder; 42 | private static String TestCase; 43 | private static String Need = "true"; 44 | private static Dimension dimension; 45 | private boolean is_running = true; 46 | private int eventcount = 0; 47 | private static String TIMING; 48 | private DriverServer driverServer; 49 | private static long EventWaitTime = 100; 50 | private static int ScreentCount = 0; 51 | private static boolean NEEDHELP = false; 52 | 53 | 54 | 55 | public static void main(String[] args) throws Exception { 56 | executeParameter(args); 57 | } 58 | 59 | 60 | /** 61 | * 执行参数 62 | * @param args 63 | * @throws Exception 64 | */ 65 | private static void executeParameter(String[] args) { 66 | int optSetting = 0; 67 | 68 | for (; optSetting < args.length; optSetting++) { 69 | for (; optSetting < args.length; optSetting++) { 70 | if ("-f".equals(args[optSetting])) { 71 | ConfigPath = args[++optSetting]; 72 | } else if ("-h".equals(args[optSetting])) { 73 | NEEDHELP = true; 74 | System.out.println("-f:配置文件"); 75 | break; 76 | } 77 | } 78 | } 79 | if (!needhelp) { 80 | Map configMap = readYaml(ConfigPath); 81 | UDID = (String) configMap.get("UDID"); 82 | BUNDLEID = (String) configMap.get("BUNDLEID"); 83 | TIMING = (String) configMap.get("TIMING"); 84 | PORT = (String) configMap.get("PORT"); 85 | PROXYPORT = (String) configMap.get("PROXYPORT"); 86 | VERBOSE = (String) configMap.get("VERBOSE"); 87 | NeedScreenshot = (String) configMap.get("NeedScreenshot"); 88 | ScreenshotFolder = (String) configMap.get("ScreenshotFolder"); 89 | VERBOSE = (String) configMap.get("VERBOSE"); 90 | TRACEPATH = (String) configMap.get("TRACEPATH"); 91 | AppiumLogFolder = (String) configMap.get("AppiumLogFolder"); 92 | TestCase = (String) configMap.get("TestCase"); 93 | 94 | try { 95 | log_info( 96 | "\n" + "测试设备:" + UDID + 97 | "\n" + "测试App:" + BUNDLEID + 98 | "\n" + "Appium端口:" + PORT + 99 | "\n" + "WDA端口:" + PROXYPORT + 100 | "\n" + "是否需要截图:" + NeedScreenshot + 101 | "\n" + "是否需要打印log:" + VERBOSE); 102 | if (VERBOSE.equals(Need)){ 103 | initLogger().setLevel(Level.ALL); 104 | }else { 105 | initLogger().setLevel(Level.WARN); 106 | } 107 | org.testng.Assert.assertTrue((!UDID.equals(null)) && (!BUNDLEID.equals(null))); 108 | } catch (Exception e) { 109 | log_info("请确认参数配置,需要帮助请输入 java -jar iosMonkey.jar -h\n" 110 | + "ERROR信息"+ e.toString()); 111 | } 112 | try { 113 | new Monkey().run(); 114 | } catch (Exception e) { 115 | e.printStackTrace(); 116 | } 117 | } 118 | } 119 | 120 | 121 | /** 122 | * 运行monkey主方法 123 | * @throws Exception 124 | */ 125 | public void run() throws Exception { 126 | log_info("查询是否有缓存崩溃文件!"); 127 | backup(); 128 | driverServer = new DriverServer(UDID,Integer.parseInt(PORT),Integer.parseInt(PROXYPORT)); 129 | driverServer.killWDAServer(); 130 | driverServer.killAppiumServer(); 131 | driverServer.startAppiumServer(AppiumLogFolder); 132 | iosDriver = driverServer.baseDriver(BUNDLEID); 133 | Screenshot SC = new Screenshot(UDID,ScreenshotFolder); 134 | log_info("本次设定的运行时长【" + TIMING + "】分钟"); 135 | long startTime = System.currentTimeMillis(); 136 | Map coordinateMap = calculateCoordinate(iosDriver); 137 | 138 | if (!TestCase.equals("")){ 139 | log_info("用例文件地址:" + TestCase); 140 | new CaseEvent(iosDriver).generateCase(TestCase); //生成case 141 | }else { 142 | log_info("未配置测试用例,进行Monkey测试!"); 143 | } 144 | 145 | if (NeedScreenshot.equals(Need)) { 146 | File outputPath = new File(Screenshot.ScreenshotFolder); 147 | if (outputPath.exists()){ 148 | FileUtils.deleteQuietly(new File(String.valueOf(outputPath))); 149 | log_info(String.format("删除%s",outputPath)); 150 | FileUtils.forceMkdir(outputPath); 151 | log_info(String.format("创建%s",outputPath)); 152 | }else { 153 | FileUtils.forceMkdir(outputPath); 154 | log_info(String.format("创建%s",outputPath)); 155 | } 156 | } 157 | 158 | Timer timer = new Timer(); 159 | //延迟0秒,并且每过5s执行一次 160 | timer.schedule(new MonkeyDaemon(UDID,BUNDLEID), 0, loopTime); 161 | 162 | GetPerformance getPerformance= new GetPerformance(); 163 | HashMap args = getPerformance.startTrace(iosDriver,TRACEPATH); 164 | try { 165 | while (is_running) { 166 | new MonkeySpecialEvent(iosDriver).closeAlert(); 167 | switch (new MathRandom().PercentageRandom()) { 168 | case 0: { 169 | int x = (int) Math.ceil(Math.random() * (width - 1)); 170 | int y = (int) Math.ceil(Math.random() * (height - 1)); 171 | if (NeedScreenshot.equals(Need)) { 172 | SC.screenshot(ScreentCount,new Double(x).intValue(), new Double(y).intValue()); 173 | ScreentCount ++; 174 | } 175 | new MonkeyTapEvent(iosDriver, x, y).injectEvent(); 176 | eventcount = eventcount+1; 177 | log_info("---EVENT执行了:"+eventcount+"次---"); 178 | break; 179 | } 180 | case 1: { 181 | new MonkeySwipeEvent(iosDriver).injectEvent_scrollDown(); 182 | eventcount = eventcount+1; 183 | log_info("---EVENT执行了:"+eventcount+"次---"); 184 | break; 185 | } 186 | case 2: { 187 | new MonkeyBackEvent(iosDriver).injectEvent(); 188 | eventcount = eventcount+1; 189 | log_info("---EVENT执行了:"+eventcount+"次---"); 190 | break; 191 | } 192 | case 3: { 193 | int x = randomSubmitCoordinate(coordinateMap)[0]; 194 | int y = randomSubmitCoordinate(coordinateMap)[1]; 195 | if (NeedScreenshot.equals(Need)){ 196 | SC.screenshot(ScreentCount,x ,y); 197 | ScreentCount ++; 198 | } 199 | new MonkeySubmitEvent(iosDriver, x, y).injectEvent(); 200 | eventcount = eventcount+1; 201 | log_info("---EVENT执行了:"+eventcount+"次---"); 202 | break; 203 | } 204 | case 4: { 205 | new MonkeyXpathEvent(iosDriver).injectEvent_Text(); 206 | eventcount = eventcount+1; 207 | log_info("---EVENT执行了:"+eventcount+"次---"); 208 | break; 209 | } 210 | case 5: { 211 | new MonkeyHomeKeyEvent(iosDriver).injectEvent(); 212 | eventcount = eventcount+1; 213 | log_info("---EVENT执行了:"+eventcount+"次---"); 214 | break; 215 | } 216 | } 217 | 218 | long endTime = System.currentTimeMillis(); 219 | if((endTime - startTime) > (Integer.parseInt(TIMING) * 60 * 1000)) { 220 | log_info("已运行" + (endTime - startTime)/60/1000 + "分钟,任务即将结束"); 221 | 222 | // 发送邮件 223 | log_info("退出守护线程!"); 224 | is_running = false; 225 | timer.cancel(); 226 | }else { 227 | Thread.sleep(EventWaitTime); 228 | long runTime = (endTime - startTime) / 1000; 229 | String p = getRunProgress(Integer.parseInt(TIMING) * 60, (int)runTime); 230 | System.out.println(String.format("当前运行进度:%s",p)); 231 | } 232 | } 233 | getPerformance.endTrace(iosDriver,args); 234 | }catch (Exception E){ 235 | log_info(this.getClass().getName() + "-" + "Run异常:" + E); 236 | } 237 | 238 | if (NeedScreenshot.equals(Need)){ 239 | createGif(Screenshot.ScreenshotFolder); //生成gif 240 | } 241 | teardown(); 242 | } 243 | 244 | 245 | 246 | public void teardown() throws IOException { 247 | ArrayList crashList = searchCrashPath(); 248 | log_info("搜索是否有崩溃日志"); 249 | int crashSize = crashList.size();; 250 | if (crashList.size() !=0 ){ 251 | String [] strings = (String[]) crashList.toArray(new String[crashSize]); 252 | for (Object str:strings ) { 253 | System.out.println(str); 254 | } 255 | System.out.println(merageCrashResult); 256 | if (mergeFiles(strings,merageCrashResult)){ 257 | }else { 258 | log_info("合并crash文件失败!"); 259 | } 260 | }else { 261 | log_info("本次运行monkey未发生崩溃!"); 262 | } 263 | 264 | } 265 | 266 | 267 | /** 268 | * 计算运行进度,保留一位小数 269 | */ 270 | public static String getRunProgress(int totalTime, int currentTime){ 271 | try { 272 | float Progress = (float) currentTime / (float)totalTime; 273 | DecimalFormat decimalFormat= new DecimalFormat(".0"); 274 | String p= decimalFormat.format(Progress * 100); 275 | return p ; 276 | }catch (Exception e) { 277 | log_info(String.format("计算运行进度异常!%s", e)); 278 | return "0"; 279 | } 280 | } 281 | 282 | 283 | 284 | /** 285 | * 计算坐标 286 | */ 287 | private Map calculateCoordinate(IOSDriver iosDriver) throws Exception { 288 | dimension = iosDriver.manage().window().getSize(); 289 | width= dimension.width; 290 | height= dimension.height; 291 | 292 | NumberFormat numberFormat = NumberFormat.getInstance(); 293 | numberFormat.setMaximumFractionDigits(2); 294 | 295 | submitX_max = width - 1; 296 | submitX_mim = width / 10; 297 | submitY_max = height - 1; 298 | submitY_mim = height / 10 * 9; 299 | contentX_max = width - width / 10; 300 | contentX_min = width / 10; 301 | contentY_max = height / 2 + height / 10; 302 | contentY_mim = height / 2 - height / 10; 303 | special_point_x = width / 2; 304 | special_point_y = (int) (height * 0.94); 305 | 306 | Map Coordinatemap = new HashMap(); 307 | Coordinatemap.put("submitX_max",submitX_max); 308 | Coordinatemap.put("submitX_mim",submitX_mim); 309 | Coordinatemap.put("submitY_max",submitY_max); 310 | Coordinatemap.put("submitY_mim",submitY_mim); 311 | Coordinatemap.put("contentX_max",contentX_max); 312 | Coordinatemap.put("contentX_min",contentX_min); 313 | Coordinatemap.put("contentY_max",contentY_max); 314 | Coordinatemap.put("contentY_mim",contentY_mim); 315 | Coordinatemap.put("special_point_x",special_point_x); 316 | Coordinatemap.put("special_point_y",special_point_y); 317 | return Coordinatemap; 318 | } 319 | 320 | /** 321 | * 计算随机坐标 322 | */ 323 | private int[] randomContentCoordinate(Map coordinateMap) throws Exception { 324 | Random random = new Random(); 325 | contentX_max = (int) coordinateMap.get("contentX_max"); 326 | contentX_min = (int) coordinateMap.get("contentX_min"); 327 | contentY_max = (int) coordinateMap.get("contentY_max"); 328 | contentY_mim = (int) coordinateMap.get("contentY_mim"); 329 | int x = random.nextInt(contentX_max) % (contentX_max - contentX_min + 1) + contentX_min; 330 | int y = random.nextInt(contentY_max) % (contentY_max - contentY_mim + 1) + contentY_mim; 331 | int[] array = {x, y}; 332 | return array; 333 | } 334 | 335 | 336 | /** 337 | * 计算随机坐标 338 | */ 339 | private int[] randomSubmitCoordinate(Map coordinateMap) throws Exception { 340 | try { 341 | Random random = new Random(); 342 | submitX_max = (int) coordinateMap.get("submitX_max"); 343 | submitX_mim = (int) coordinateMap.get("submitX_mim"); 344 | submitY_max = (int) coordinateMap.get("submitY_max"); 345 | submitY_mim = (int) coordinateMap.get("submitY_mim"); 346 | int x = random.nextInt(submitX_max) % (submitX_max - submitX_mim + 1) + submitX_mim; 347 | int y = random.nextInt(submitY_max) % (submitY_max - submitY_mim + 1) + submitY_mim; 348 | int[] array = {x, y}; 349 | return array; 350 | }catch (Exception E){ 351 | log_info(this.getClass().getName() + "-" + "计算随机坐标异常:" + E); 352 | int[] array = {0, 0}; 353 | return array; 354 | } 355 | } 356 | } 357 | -------------------------------------------------------------------------------- /src/main/java/ScreenShots/ModifyPic.java: -------------------------------------------------------------------------------- 1 | package ScreenShots; 2 | 3 | import javax.imageio.ImageIO; 4 | import java.awt.*; 5 | import java.awt.image.BufferedImage; 6 | import java.io.File; 7 | import java.io.IOException; 8 | import static Untils.MyLogger.log_info; 9 | 10 | 11 | public class ModifyPic { 12 | private Font font = new Font("", Font.PLAIN, 20);// 添加字体的属性设置 13 | private Graphics2D g = null; 14 | private int fontsize; 15 | private int x; 16 | private int y; 17 | private String imgSrcPath; 18 | private String imgDesPath; 19 | private String content; 20 | private String fontStyle; 21 | private Color color; 22 | 23 | /** 24 | * 导入本地图片到缓冲区 25 | */ 26 | public BufferedImage loadImageLocal(String imgSrcPath) { 27 | try { 28 | this.imgSrcPath = imgSrcPath; 29 | return ImageIO.read(new File(this.imgSrcPath)); 30 | } catch (IOException e) { 31 | log_info(e.getMessage()); 32 | } 33 | return null; 34 | } 35 | 36 | /** 37 | * 生成新图片到本地 38 | */ 39 | public void writeImageLocal(String imgDesPath, BufferedImage img) { 40 | if (imgDesPath != null && img != null) { 41 | try { 42 | this.imgDesPath = imgDesPath; 43 | File outputfile = new File(this.imgDesPath); 44 | ImageIO.write(img, "png", outputfile); 45 | } catch (IOException e) { 46 | log_info(e.getMessage()); 47 | } 48 | } 49 | } 50 | 51 | /** 52 | * 设定文字的字体等 53 | */ 54 | public void setFont(String fontStyle, int fontSize) { 55 | this.fontsize = fontSize; 56 | this.fontStyle = fontStyle; 57 | this.font = new Font(this.fontStyle, Font.PLAIN, this.fontsize); 58 | } 59 | 60 | /** 61 | * 设定文字在图片中的位置以及文字的颜色 62 | * @param x 63 | * @param y 64 | * @param color 65 | */ 66 | public void setLocalColor(int x,int y,Color color){ 67 | this.x = x; 68 | this.y = y; 69 | this.color=color; 70 | } 71 | 72 | /** 73 | * 修改图片,返回修改后的图片缓冲区(只输出一行文本) 74 | */ 75 | public BufferedImage modifyImage(BufferedImage img, String content) { 76 | try { 77 | int w = img.getWidth(); 78 | int h = img.getHeight(); 79 | g = img.createGraphics(); 80 | //g.setBackground(Color.WHITE); 81 | g.setColor(this.color); 82 | if (this.font != null) 83 | g.setFont(this.font); 84 | // 验证输出位置的纵坐标和横坐标 85 | if (x >= h || y >= w) { 86 | this.x = h - this.fontsize + 2; 87 | this.y = w; 88 | } 89 | this.content=content; 90 | if (content != null) { 91 | g.drawString(this.content, this.x, this.y); 92 | } 93 | g.dispose(); 94 | } catch (Exception e) { 95 | log_info(e.getMessage()); 96 | } 97 | return img; 98 | } 99 | 100 | 101 | public ModifyPic(String imgSrcPath, String imgDesPath, String content, 102 | String fontStyle, int fontsize, int x, int y,Color color) { 103 | super(); 104 | this.fontsize = fontsize; 105 | this.x = x; 106 | this.y = y; 107 | this.imgSrcPath = imgSrcPath; 108 | this.imgDesPath = imgDesPath; 109 | this.content = content; 110 | this.fontStyle = fontStyle; 111 | this.color=color; 112 | setFont(fontStyle, fontsize); 113 | writeImageLocal(imgDesPath, modifyImage(loadImageLocal(imgSrcPath), content)); 114 | } 115 | 116 | 117 | public ModifyPic(String fontStyle, int fontsize, int x, int y,Color color) { 118 | super(); 119 | this.fontsize = fontsize; 120 | this.x = x; 121 | this.y = y; 122 | this.fontStyle = fontStyle; 123 | this.color=color; 124 | setFont(fontStyle, fontsize); 125 | setLocalColor(x,y,color); 126 | } 127 | 128 | 129 | } 130 | -------------------------------------------------------------------------------- /src/main/java/ScreenShots/Screenshot.java: -------------------------------------------------------------------------------- 1 | package ScreenShots; 2 | 3 | import java.awt.*; 4 | import java.io.File; 5 | import java.io.IOException; 6 | import static Untils.MyLogger.log_info; 7 | 8 | 9 | /** 10 | * @author xinxi 11 | * 截图 12 | */ 13 | 14 | public class Screenshot { 15 | 16 | public static String projectPath = System.getProperty("user.dir"); 17 | public static String ScreenshotFolder; 18 | public static String screenshotPath1 ; 19 | public static String screenshotPath2 ; 20 | public static String udid; 21 | private static int waitShot = 500; 22 | 23 | public Screenshot(String UDID,String Folder) { 24 | udid = UDID; 25 | ScreenshotFolder = String.format(Folder + "/", udid); 26 | File file = new File(ScreenshotFolder); 27 | if (! file.exists()){ 28 | file.mkdir(); 29 | log_info("创建保存图片文件夹:" + ScreenshotFolder); 30 | } 31 | } 32 | 33 | public void screenshot(int COUNT, int x, int y) throws InterruptedException { 34 | //File file = new File(projectPath); 35 | //String RootPath = file.getParent(); 36 | //log_info("文件的上级目录为 : " + RootPath); 37 | screenshotPath1 = ScreenshotFolder + "iOSMonkey.png"; 38 | screenshotPath2 = ScreenshotFolder + String.format("iOSMonkey%s.png",String.format("%03d", COUNT)); 39 | String screenshotCmd = String.format("xcrun simctl io booted screenshot %s", screenshotPath1); 40 | log_info("截图命令:" + screenshotCmd); 41 | 42 | if (udid.contains("-")) { 43 | try { 44 | Process pp = Runtime.getRuntime().exec(screenshotCmd); 45 | pp.waitFor(); 46 | } catch (IOException e) { 47 | e.printStackTrace(); 48 | } catch (InterruptedException e) { 49 | e.printStackTrace(); 50 | } 51 | } else { 52 | try { 53 | Runtime.getRuntime().exec("idevicescreenshot -u " + udid + " " + screenshotPath1); 54 | } catch (IOException e) { 55 | e.printStackTrace(); 56 | } 57 | } 58 | Thread.sleep(waitShot); 59 | File file1 = new File(screenshotPath1); 60 | if (file1.exists() && file1.length() > 0) { 61 | new ModifyPic(screenshotPath1, screenshotPath2, "◯", "STYLE_ITALIC", 50, x, y, Color.RED); 62 | log_info("create ScreenShots : " + screenshotPath2); 63 | file1.delete(); 64 | } else if (file1.exists() && file1.length() <= 0) { 65 | file1.delete(); 66 | } else { 67 | log_info("截图失败,并没有找到截图文件!"); 68 | } 69 | 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/Test.java: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | import java.nio.Buffer; 3 | import java.sql.Time; 4 | import java.text.DecimalFormat; 5 | 6 | import static Untils.MyLogger.log_info; 7 | 8 | public class Test { 9 | 10 | 11 | public static void main(String[] args) throws InterruptedException, IOException { 12 | 13 | // while (true){ 14 | // new Test().run("DDAC13B0-786D-4DC7-A920-4BEAF56CD616"); 15 | // Thread.sleep(1000); 16 | // } 17 | 18 | //System.out.println(getRunProgress(3600,2000)); 19 | 20 | long a = System.currentTimeMillis(); 21 | System.out.println(a); 22 | Thread.sleep(2000); 23 | long b = System.currentTimeMillis(); 24 | System.out.println(b); 25 | System.out.println(b-a); 26 | 27 | 28 | 29 | 30 | } 31 | 32 | 33 | 34 | public void run(String UDID) { 35 | if (UDID.contains("-")){ 36 | log_info("模拟器检查app运行状态!"); 37 | String runcmd = "xcrun simctl spawn booted log stream --level=debug"; 38 | Process pp = null; 39 | try { 40 | pp = Runtime.getRuntime().exec(runcmd); 41 | } catch (IOException e) { 42 | e.printStackTrace(); 43 | } 44 | BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(pp.getInputStream())); 45 | String line; 46 | int lineCount = 0; 47 | String runstring = ""; 48 | try { 49 | while ((line = bufferedReader.readLine()) != null) { 50 | lineCount++; 51 | if (lineCount < 5) { 52 | runstring += line + "\n"; 53 | }else { 54 | break; 55 | } 56 | } 57 | } catch (IOException e) { 58 | e.printStackTrace(); 59 | }finally { 60 | System.out.println(runstring); 61 | if (runstring.contains("LuoJiFMIOS")) { 62 | log_info("模拟器app运行中!"); 63 | } else { 64 | log_info("模拟器app不在运行中!"); 65 | log_info("====非测试APP,重新呼起测试APP===="); 66 | //Runtime.getRuntime().exec("xcrun simctl launch booted " + BUNDLEID); 67 | } 68 | } 69 | }else { 70 | log_info("真机检查app运行状态!"); 71 | } 72 | } 73 | 74 | 75 | 76 | 77 | /** 78 | * 计算运行进度,保留一位小数 79 | */ 80 | public static String getRunProgress(int totalTime, int currentTime){ 81 | try { 82 | float Progress = (float) currentTime / (float)totalTime; 83 | DecimalFormat decimalFormat= new DecimalFormat(".0"); 84 | String p= decimalFormat.format(Progress * 100); 85 | return p ; 86 | }catch (Exception e) { 87 | log_info(String.format("计算运行进度异常!%s", e)); 88 | return "0"; 89 | } 90 | } 91 | 92 | 93 | 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/Untils/FileUntils.java: -------------------------------------------------------------------------------- 1 | package Untils; 2 | 3 | import org.yaml.snakeyaml.Yaml; 4 | import java.io.File; 5 | import java.io.FileInputStream; 6 | import java.text.SimpleDateFormat; 7 | import java.util.Calendar; 8 | import java.util.Date; 9 | import java.util.List; 10 | import java.util.Map; 11 | import java.util.regex.Matcher; 12 | import java.util.regex.Pattern; 13 | import static Untils.MyLogger.log_info; 14 | 15 | 16 | public class FileUntils { 17 | 18 | 19 | public static String timeDate(){ 20 | Date now = new Date(); 21 | SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); 22 | String timestr = dateFormat.format(now); 23 | return timestr; 24 | } 25 | 26 | /** 27 | * 用当前日期生成唯一序列号 28 | * 格式:年+月+日+小时+分钟 29 | * 20150421113300 30 | * @return 31 | */ 32 | public static String currentTime(){ 33 | SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 34 | Calendar cal = Calendar.getInstance(); 35 | String times = format.format(cal.getTime()).substring(0,19); 36 | Pattern pattern = Pattern.compile("[^0-9]"); 37 | Matcher matcher = pattern.matcher(times); 38 | StringBuffer sbr = new StringBuffer(); 39 | while (matcher.find()) { 40 | matcher.appendReplacement(sbr,""); 41 | } 42 | matcher.appendTail(sbr); 43 | //System.out.println(sbr.toString()); 44 | return sbr.toString(); 45 | } 46 | 47 | public static void sleep(double d) { 48 | try { 49 | d *= 1000; 50 | Thread.sleep((int)d); 51 | } catch (Exception e){} 52 | } 53 | 54 | 55 | /** 56 | * 读Yaml文件 57 | * param YamlName 58 | * return Map类型 59 | */ 60 | public static Map readYaml(String yamlpath) { 61 | 62 | Map map = null; 63 | try{ 64 | File dumpFile = new File(yamlpath); 65 | Yaml yaml = new Yaml(); 66 | map = (Map) yaml.load((new FileInputStream(dumpFile))); 67 | }catch (Exception e){ 68 | System.out.println(String.format("读取%s异常! + \n + %s", yamlpath,e)); 69 | } 70 | return map; 71 | } 72 | 73 | 74 | /** 75 | * 读Yaml文件 76 | * param YamlName 77 | * return Map类型 78 | */ 79 | public static List readYamlList(String yamlpath) { 80 | 81 | List list = null; 82 | try{ 83 | File dumpFile = new File(yamlpath); 84 | Yaml yaml = new Yaml(); 85 | list = yaml.load((new FileInputStream(dumpFile))); 86 | }catch (Exception e){ 87 | System.out.println(String.format("读取%s异常! + \n + %s", yamlpath,e)); 88 | } 89 | return list; 90 | } 91 | 92 | 93 | /** 94 | * 生成gif 95 | */ 96 | public static void createGif(String folderPath){ 97 | try { 98 | String pngPath = folderPath + "iOSMonkey%03d.png"; 99 | String gifPath = folderPath + "iOSMonkey.gif"; 100 | String cmd = "ffmpeg -f image2 -framerate 1 -i " + pngPath + " -y " + gifPath; 101 | log_info(String.format("合并gif命令:%s", cmd)); 102 | Runtime.getRuntime().exec(cmd); 103 | log_info("生成gif地址:" + gifPath ); 104 | }catch (Exception E){ 105 | log_info("生成gif异常:" + E); 106 | } 107 | } 108 | 109 | public static void main(String[] args) { 110 | Map map = readYaml("./config/config.yaml"); 111 | System.out.println(map); 112 | } 113 | 114 | 115 | 116 | } 117 | -------------------------------------------------------------------------------- /src/main/java/Untils/GetPerformance.java: -------------------------------------------------------------------------------- 1 | package Untils; 2 | 3 | import io.appium.java_client.ios.IOSDriver; 4 | import java.io.File; 5 | import java.io.FileNotFoundException; 6 | import java.io.FileOutputStream; 7 | import java.io.IOException; 8 | import java.util.Base64; 9 | import java.util.HashMap; 10 | 11 | /** 12 | * @author xinxi 13 | * 获取iOS性能日志 14 | */ 15 | 16 | public class GetPerformance { 17 | 18 | 19 | private File traceZip; 20 | 21 | public HashMap startTrace(IOSDriver iosDriver,String tracePath){ 22 | traceZip = new File(tracePath + "/trace.zip"); 23 | HashMap args = new HashMap<>(); 24 | args.put("timeout", 60000); 25 | args.put("pid", "current"); 26 | args.put("profileName", "Time Profiler"); 27 | iosDriver.executeScript("mobile: startPerfRecord", args); 28 | return args; 29 | } 30 | 31 | 32 | public void endTrace(IOSDriver iosDriver, HashMap args) throws IOException { 33 | args = new HashMap<>(); 34 | args.put("profileName", "Time Profiler"); 35 | String b64Zip = (String)iosDriver.executeScript("mobile: stopPerfRecord", args); 36 | byte[] bytesZip = Base64.getMimeDecoder().decode(b64Zip); 37 | FileOutputStream stream = new FileOutputStream(traceZip); 38 | stream.write(bytesZip); 39 | } 40 | 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/Untils/MailConfig.java: -------------------------------------------------------------------------------- 1 | package Untils; 2 | 3 | public class MailConfig { 4 | // 设置服务器,用户名、口令以及邮箱的后缀 5 | protected static String mail_host = "smtp.exmail.qq.com"; 6 | protected static String mail_user = "xxxx"; 7 | protected static String mail_pwd = "xxxx"; 8 | protected static String mail_postfix = "xxxxx"; 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/Untils/MyLogger.java: -------------------------------------------------------------------------------- 1 | package Untils; 2 | 3 | import org.apache.log4j.Level; 4 | import org.apache.log4j.Logger; 5 | 6 | public class MyLogger { 7 | 8 | public static Logger logger; 9 | 10 | /** 11 | * 初始化logger 12 | */ 13 | public static Logger initLogger(){ 14 | logger = Logger.getLogger("iOSMonkey"); 15 | return logger; 16 | } 17 | 18 | /** 19 | * info日志 20 | */ 21 | public static void log_info(String text){ 22 | initLogger().info(text); 23 | } 24 | 25 | /** 26 | * debug日志 27 | */ 28 | public static void log_debug(String text){ 29 | initLogger().info(text); 30 | } 31 | 32 | public static void main(String[] args) { 33 | initLogger().setLevel(Level.ALL); 34 | initLogger().info("test111"); 35 | 36 | } 37 | 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/Untils/SearchCrash.java: -------------------------------------------------------------------------------- 1 | package Untils; 2 | 3 | import org.apache.http.util.TextUtils; 4 | import java.io.*; 5 | import java.nio.channels.FileChannel; 6 | import java.text.SimpleDateFormat; 7 | import java.util.ArrayList; 8 | import java.util.Date; 9 | 10 | import static Untils.MyLogger.log_info; 11 | 12 | /** 13 | * @author xinxi 14 | * 运行完monkey查询崩溃日志 15 | */ 16 | 17 | 18 | public class SearchCrash { 19 | 20 | public static String startStr = "xxxxxxxx"; 21 | public static String endStr = ".crash"; 22 | public static String rootPath; 23 | 24 | static { 25 | try { 26 | rootPath = getRootPath() +"/Library/Logs/DiagnosticReports"; 27 | } catch (IOException e) { 28 | e.printStackTrace(); 29 | } catch (InterruptedException e) { 30 | e.printStackTrace(); 31 | } 32 | } 33 | 34 | public static String backupPath; 35 | 36 | static { 37 | try { 38 | backupPath = getRootPath() + "/Library/Logs/DiagnosticReports/backups"; 39 | } catch (IOException e) { 40 | e.printStackTrace(); 41 | } catch (InterruptedException e) { 42 | e.printStackTrace(); 43 | } 44 | } 45 | 46 | public static String merageCrashResult; 47 | 48 | static { 49 | try { 50 | merageCrashResult = String.format( getRootPath() + "/Library/Logs/DiagnosticReports/ios_crash_%s.log", getCurrentTime()); 51 | } catch (IOException e) { 52 | e.printStackTrace(); 53 | } catch (InterruptedException e) { 54 | e.printStackTrace(); 55 | } 56 | } 57 | 58 | public static void main(String[] args) throws IOException, InterruptedException { 59 | //backup(); 60 | // ArrayList arrayList = new ArrayList(); 61 | // arrayList.add("/Users/xinxi/Library/Logs/DiagnosticReports/backups/LuoJiFMIOS_2018-11-15-143820_xinxideMacBook-Pro.crash"); 62 | // arrayList.add("/Users/xinxi/Library/Logs/DiagnosticReports/backups/LuoJiFMIOS_2018-11-15-143839_xinxideMacBook-Pro.crash"); 63 | // int size = arrayList.size(); 64 | // String [] strings = (String[]) arrayList.toArray(new String[size]); 65 | // mergeFiles(strings,merageCrashResult); 66 | 67 | System.out.println(getRootPath()); 68 | 69 | } 70 | 71 | 72 | /** 73 | * 查询模拟崩溃日志全路径 74 | */ 75 | public static ArrayList searchCrashPath() throws IOException { 76 | ArrayList arrayList = new ArrayList(); 77 | InputStreamReader stdISR = null; 78 | InputStreamReader errISR = null; 79 | String[] command = { "sh", "-c", "ls " + rootPath }; 80 | Process process = null; 81 | try { 82 | process = Runtime.getRuntime().exec(command); 83 | process.waitFor(); 84 | String line = null; 85 | stdISR = new InputStreamReader(process.getInputStream()); 86 | BufferedReader stdBR = new BufferedReader(stdISR); 87 | while ((line = stdBR.readLine()) != null) { 88 | if (line.startsWith(startStr) && line.endsWith(endStr)){ 89 | String fullPath = rootPath + "/" + line; 90 | arrayList.add(fullPath); 91 | } 92 | } 93 | } catch (IOException | InterruptedException e) { 94 | e.printStackTrace(); 95 | } 96 | return arrayList; 97 | } 98 | 99 | 100 | 101 | /** 102 | * 查询模拟崩溃日志 103 | */ 104 | public static ArrayList searchCrashLogs() throws IOException { 105 | ArrayList arrayList = new ArrayList(); 106 | InputStreamReader stdISR = null; 107 | InputStreamReader errISR = null; 108 | String[] command = { "sh", "-c", "ls " + rootPath }; 109 | Process process = null; 110 | try { 111 | process = Runtime.getRuntime().exec(command); 112 | process.waitFor(); 113 | String line = null; 114 | stdISR = new InputStreamReader(process.getInputStream()); 115 | BufferedReader stdBR = new BufferedReader(stdISR); 116 | while ((line = stdBR.readLine()) != null) { 117 | if (line.startsWith(startStr) && line.endsWith(endStr)){ 118 | arrayList.add(line); 119 | } 120 | } 121 | } catch (IOException | InterruptedException e) { 122 | e.printStackTrace(); 123 | } 124 | return arrayList; 125 | } 126 | 127 | 128 | /** 129 | * 备份崩溃日志 130 | */ 131 | public static void backup() throws IOException { 132 | ArrayList arrayList = searchCrashLogs(); 133 | Process process = null; 134 | if (arrayList.size() != 0){ 135 | for (Object source:arrayList) { 136 | System.out.println(source); 137 | try { 138 | String sourcePath = rootPath + "/" + source; 139 | String destinationPath = backupPath+ "/" + source; 140 | String[] command = { "sh", "-c", String.format("mv %s %s",sourcePath,destinationPath)}; 141 | Runtime.getRuntime().exec(command); 142 | log_info(String.format("从%s移动到%s",sourcePath,destinationPath)); 143 | } catch (IOException e) { 144 | //moving file failed. 145 | e.printStackTrace(); 146 | } 147 | } 148 | log_info("移动崩溃日志完成!"); 149 | }else { 150 | log_info("未查询到崩溃日志!"); 151 | } 152 | } 153 | 154 | 155 | 156 | /** 157 | * 获取电脑根目录地址 158 | * @throws IOException 159 | * @throws InterruptedException 160 | */ 161 | public static String getRootPath() throws IOException, InterruptedException { 162 | InputStreamReader stdISR = null; 163 | InputStreamReader errISR = null; 164 | Process process = null; 165 | String rootName = null; 166 | String[] command = {"sh", "-c", "echo $HOME"}; 167 | try { 168 | process = Runtime.getRuntime().exec(command); 169 | process.waitFor(); 170 | String line = null; 171 | stdISR = new InputStreamReader(process.getInputStream()); 172 | BufferedReader stdBR = new BufferedReader(stdISR); 173 | while ((line = stdBR.readLine()) != null) { 174 | rootName = line; 175 | 176 | } 177 | } catch (IOException | InterruptedException e) { 178 | e.printStackTrace(); 179 | } 180 | return rootName; 181 | 182 | 183 | 184 | } 185 | 186 | 187 | /** 188 | * 文件合并 189 | * @param fpaths 190 | * @param resultPath 191 | * @return 192 | */ 193 | public static boolean mergeFiles(String[] fpaths, String resultPath) { 194 | if (fpaths == null || fpaths.length < 1 || TextUtils.isEmpty(resultPath)) { 195 | return false; 196 | } 197 | if (fpaths.length == 1) { 198 | return new File(fpaths[0]).renameTo(new File(resultPath)); 199 | } 200 | File[] files = new File[fpaths.length]; 201 | for (int i = 0; i < fpaths.length; i ++) { 202 | files[i] = new File(fpaths[i]); 203 | if (TextUtils.isEmpty(fpaths[i]) || !files[i].exists() || !files[i].isFile()) { 204 | return false; 205 | } 206 | } 207 | File resultFile = new File(resultPath); 208 | try { 209 | FileChannel resultFileChannel = new FileOutputStream(resultFile, true).getChannel(); 210 | for (int i = 0; i < fpaths.length; i ++) { 211 | FileChannel blk = new FileInputStream(files[i]).getChannel(); 212 | resultFileChannel.transferFrom(blk, resultFileChannel.size(), blk.size()); 213 | blk.close(); 214 | } 215 | resultFileChannel.close(); 216 | } catch (FileNotFoundException e) { 217 | e.printStackTrace(); 218 | return false; 219 | } catch (IOException e) { 220 | e.printStackTrace(); 221 | return false; 222 | } 223 | for (int i = 0; i < fpaths.length; i ++) { 224 | files[i].delete(); 225 | } 226 | return true; 227 | } 228 | 229 | public static String getCurrentTime(){ 230 | SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");//设置日期格式 231 | String CurrentTime = df.format(new Date()); 232 | log_info("当前时间:" + CurrentTime); 233 | return CurrentTime; 234 | } 235 | 236 | } 237 | -------------------------------------------------------------------------------- /src/main/java/Untils/SendMail.java: -------------------------------------------------------------------------------- 1 | package Untils; 2 | 3 | 4 | import javax.activation.DataHandler; 5 | import javax.activation.DataSource; 6 | import javax.activation.FileDataSource; 7 | import javax.mail.*; 8 | import javax.mail.internet.*; 9 | import java.io.File; 10 | import java.io.IOException; 11 | import java.io.UnsupportedEncodingException; 12 | import java.text.SimpleDateFormat; 13 | import java.util.*; 14 | import static Untils.MyLogger.log_info; 15 | 16 | /** 17 | * @author xinxi 18 | * 发送测试报告 19 | */ 20 | 21 | public class SendMail { 22 | public static Properties properties; 23 | public static String from; 24 | public static String username; 25 | public static String password; 26 | public static String host; 27 | public static Session session; 28 | public static String Subject; 29 | public static String Content = getCurrentTime() + "\n" + String.format("具体%s详见附件!", Subject) + 30 | "\n" + "如附件中文件格式丢失,请手动改成.html格式!"; 31 | private static String mailist; 32 | private static String newPathName; 33 | private static String taskOver = "完成"; 34 | 35 | public static void main(String [] args) throws IOException, InterruptedException { 36 | 37 | 38 | } 39 | 40 | 41 | /** 42 | * 拼接接收者地址 43 | * @param mailist 44 | * @return 45 | */ 46 | public static InternetAddress[] Address(String mailist){ 47 | //多个接收账号 48 | InternetAddress[] address=null; 49 | try { 50 | List list = new ArrayList(); 51 | //不能使用string类型的类型,这样只能发送一个收件人 52 | String []median=mailist.split(","); 53 | //对输入的多个邮件进行逗号分割 54 | for(int i=0;i