文章出處http://blog.csdn.net/jiuzuidongpo/article/details/51790455
Appium在接收到客戶端腳本的連接之后的初始化准備工作列表(細節部分詳細敘述,只說重點):
下面提到的有關目錄是自己的本地目錄,需要注意。
1,檢查app包是否存在,檢查adb工具是否可用,檢查java工具包版本。
2,確定設備,用命令
adb.exe devices
選擇指定udid的設備
3,確定設備是否准備好,命令
adb.exe -s 16144573 wait-for-device
adb.exe -s 16144573 shell "echo 'ready'"
如果命令行輸出ready,則表示准備好
4,檢查設備的API版本號,命令
adb.exe -s 16144573 shell "getprop ro.build.version.sdk"
如果>=17,則可用
5,語言設置
獲取設備當前使用語言(一般返回zh)
adb.exe -s 16144573 shell "getprop persist.sys.language"
生成string.json
java -jar "C:\Program Files (x86)\Appium\node_modules\appium\node_modules\appium-adb\jars\appium_apk_tools.jar" "stringsFromApk" "E:\workspace\appium-test\sample\apps\ContactManager\ContactManager.apk" "C:\Users\ADMINI~1\AppData\Local\Temp\com.example.android.contactmanager" zh
如果報錯,則執行下面,生成string.json
java -jar "C:\Program Files (x86)\Appium\node_modules\appium\node_modules\appium-adb\jars\appium_apk_tools.jar" "stringsFromApk" "E:\workspace\appium-test\sample\apps\ContactManager\ContactManager.apk" "C:\Users\ADMINI~1\AppData\Local\Temp\com.example.android.contactmanager"
然后從string.json設置成默認語言
D:\soft\android-sdk-windows\platform-tools\adb.exe -s 16144573 push "C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\com.example.android.contactmanager\\strings.json" /data/local/tmp
6,檢查aapt工具,並且用aapt工具分析apk包。
D:\soft\android-sdk-windows\build-tools\23.0.1\aapt.exe dump xmltree E:\workspace\appium-test\sample\apps\ContactManager\ContactManager.apk AndroidManifest.xml
獲取到apk的進程名稱:com.example.android.contactmanager,(如果指定的話,則沒必要獲取)。
和開始的activity:.ContactManager,(如果指定的話,沒必要去獲取)。
7,注冊認證apk包
java -jar "C:\Program Files (x86)\Appium\node_modules\appium\node_modules\appium-adb\jars\verify.jar" E:\workspace\appium-test\sample\apps\ContactManager\ContactManager.apk
8,壓縮apk包(Zip-aligning),並且放入手機中,這個過程有點兒復雜。
D:\soft\android-sdk-windows\build-tools\23.0.1\zipalign.exe -f 4 E:\workspace\appium-test\sample\apps\ContactManager\ContactManager.apk C:\Users\ADMINI~1\AppData\Local\Temp\116530-6572-vjd4bu\appium.tmp
獲取MD5
MD5 for app is b2d2916bb5388e1dc281ec3e71ef1234
查看apk是否存在
D:\soft\android-sdk-windows\platform-tools\adb.exe -s 16144573 shell "ls /data/local/tmp/b2d2916bb5388e1dc281ec3e71ef1234.apk"
查看apk是否安裝
D:\soft\android-sdk-windows\platform-tools\adb.exe -s 16144573 shell "pm list packages -3 com.example.android.contactmanager"
創建文件夾
D:\soft\android-sdk-windows\platform-tools\adb.exe -s 16144573 shell "mkdir -p /data/local/tmp/"
查看存在的apk
D:\soft\android-sdk-windows\platform-tools\adb.exe -s 16144573 shell "ls /data/local/tmp/*.apk"
刪除存在的apk
D:\soft\android-sdk-windows\platform-tools\adb.exe -s 16144573 shell rm "/data/local/tmp/29649242b53e9a67ba855b067422713c.apk"
放入手機中
D:\soft\android-sdk-windows\platform-tools\adb.exe -s 16144573 push "E:\\workspace\\appium-test\\sample\\apps\\ContactManager\\ContactManager.apk" /data/local/tmp/b2d2916bb5388e1dc281ec3e71ef1234.apk
停止之前運行的
D:\soft\android-sdk-windows\platform-tools\adb.exe -s 16144573 shell "am force-stop com.example.android.contactmanager"
D:\soft\android-sdk-windows\platform-tools\adb.exe -s 16144573 shell "pm clear com.example.android.contactmanager"
卸載之前運行的
D:\soft\android-sdk-windows\platform-tools\adb.exe -s 16144573 uninstall com.example.android.contactmanager
安裝新apk包
D:\soft\android-sdk-windows\platform-tools\adb.exe -s 16144573 shell "pm install -r /data/local/tmp/b2d2916bb5388e1dc281ec3e71ef1234.apk"
9,綁定本機和boostrap通信的端口號
D:\soft\android-sdk-windows\platform-tools\adb.exe -s 16144573 forward tcp:4724 tcp:4724
10,將bootstrap.jar放入手機中
D:\soft\android-sdk-windows\platform-tools\adb.exe -s 16144573 push "C:\\Program Files (x86)\\Appium\\node_modules\\appium\\build\\android_bootstrap\\AppiumBootstrap.jar" /data/local/tmp/
11,讓Unicode鍵盤可用
將Unicode輸入法push到手機中
D:\soft\android-sdk-windows\platform-tools\adb.exe -s 16144573 install "C:\Program Files (x86)\Appium\node_modules\appium\build\unicode_ime_apk\UnicodeIME-debug.apk"
獲取手機當前的輸入法,測試之后要恢復這個輸入法
D:\soft\android-sdk-windows\platform-tools\adb.exe -s 16144573 shell "settings get secure default_input_method"
設置unicode鍵盤可用,並且為當前系統的默認輸入法
D:\soft\android-sdk-windows\platform-tools\adb.exe -s 16144573 shell "ime enable io.appium.android.ime/.UnicodeIME"
D:\soft\android-sdk-windows\platform-tools\adb.exe -s 16144573 shell "ime set io.appium.android.ime/.UnicodeIME"
12,安裝appiium的setting和unlock測試包
unlock
D:\soft\android-sdk-windows\platform-tools\adb.exe -s 16144573 install "C:\Program Files (x86)\Appium\node_modules\appium\build\unlock_apk\unlock_apk-debug.apk"
Setting
D:\soft\android-sdk-windows\platform-tools\adb.exe -s 16144573 install "C:\Program Files (x86)\Appium\node_modules\appium\build\settings_apk\settings_apk-debug.apk"
13,啟動手機上的bootstrap。
首先停止手機上之前的boostrap:
獲取當前運行的boostrap
D:\soft\android-sdk-windows\platform-tools\adb.exe -s 16144573 shell "ps 'uiautomator'"
獲取到進程號16324,然后殺死
D:\soft\android-sdk-windows\platform-tools\adb.exe -s 16144573 shell "kill 16324"
然后開始當前的boostrap
D:\soft\android-sdk-windows\platform-tools\adb.exe -s 16144573 shell uiautomator runtest AppiumBootstrap.jar -c io.appium.android.bootstrap.Bootstrap -e pkg com.example.android.contactmanager -e disableAndroidWatchers false
14,然后就可以用socket和手機通信了,通信的前三步
第一步:
向手機端發送:{"cmd":"action","action":"wake","params":{}}
使手機覺醒,並且判斷鎖屏的情況(這個有待研究),如果鎖屏,運行unlock可以解鎖
D:\soft\android-sdk-windows\platform-tools\adb.exe -s NVY9AUSO5SAELRSC shell "am start -S -a android.intent.action.MAIN -c android.intent.category.LAUNCHER -f 0x10200000 -n io.appium.unlock/.Unlock"
第二步:
向手機發送:{"cmd":"action","action":"getDataDir","params":{}}
獲取數據存放路徑,正常返回{"value":"\/data\/local\/tmp","status":0},好像沒啥用
再發送
{"cmd":"action","action":"compressedLayoutHierarchy","params":{"compressLayout":false}}
返回{"value":false,"status":0}
是某個支持項。
第三步:
啟動要測試的apk
D:\soft\android-sdk-windows\platform-tools\adb.exe -s NVY9AUSO5SAELRSC shell "am start -S -a android.intent.action.MAIN -c android.intent.category.LAUNCHER -f 0x10200000 -n com.example.android.contactmanager/.ContactManager"
讓app獲得當前的焦點
D:\soft\android-sdk-windows\platform-tools\adb.exe -s NVY9AUSO5SAELRSC shell "dumpsys window windows"
- 1. 建立session時常用命令:
DesiredCapabilities cap = new DesiredCapabilities(); cap.SetCapability("browserName", ""); // web 瀏覽器名稱('Safari' ,'Chrome'等)。如果對應用進行自動化測試,這個關鍵字的值應為空。 cap.SetCapability("platformName", "Android");//你要測試的手機操作系統 cap.SetCapability("platformVersion", "4.4");//手機操作系統版本 cap.SetCapability("automationName", "selendroid"); //你想使用的自動化測試引擎:Appium (默認) 或 Selendroid cap.SetCapability("deviceName", " Android Emulator"); //使用的手機類型或模擬器類型,真機時輸入Android Emulator或者手機型號 cap.SetCapability("udid", udid); //連接的物理設備的唯一設備標識,Android可以不設置 cap.SetCapability("newCommandTimeout", "300"); //設置收到下一條命令的超時時間,超時appium會自動關閉session ,默認60秒 cap.SetCapability("unicodeKeyboard", "True");//支持中文輸入,會自動安裝Unicode 輸入法。默認值為 false cap.SetCapability("resetKeyboard", "True"); //在設定了 unicodeKeyboard 關鍵字的 Unicode 測試結束后,重置輸入法到原有狀態 cap.SetCapability("'app'", "D:\\AndroidAutomation\\AndroidAutoTest\\app\\zhongchou.apk"); //未安裝應用時,設置app的路徑 //手機已安裝app,直接從手機啟動app,上面路徑不設置 cap.SetCapability("appPackage", "com.nbbank"); //你要啟動的Android 應用對應的Activity名稱|比如`MainActivity`, `.Settings`| cap.SetCapability("appActivity", "com.nbbank.ui.ActivityShow"); //你想運行的Android應用的包名 cap.SetCapability("appWaitActivity", "com.nbbank.ui.ActivityLogo"); //你想要等待啟動的Android Activity名稱|比如`SplashActivity`| Uri serverUri = new Uri("http://127.0.0.1:4723/wd/hub"); driver = new AndroidDriver<IWebElement>(serverUri, cap, TimeSpan.FromSeconds(180));
更多詳細查看官網:https://github.com/appium/appium/blob/master/docs/cn/writing-running-appium/caps.cn.md
- 2. driver常用方法及注意事項
1) 常用方法:
driver.HideKeyboard();//隱藏鍵盤 driver.BackgroundApp(60);//60秒后把當前應用放到后台去 driver.LockDevice(3); //鎖定屏幕 //在當前應用中打開一個 activity 或者啟動一個新應用並打開一個 activity driver.StartActivity("com.iwobanas.screenrecorder.pro", "com.iwobanas.screenrecorder.RecorderActivity"); driver.OpenNotifications();//打開下拉通知欄 只能在 Android 上使用 driver.IsAppInstalled("com.example.android.apis-");//檢查應用是否已經安裝 driver.InstallApp("path/to/my.apk");//安裝應用到設備中去 driver.RemoveApp("com.example.android.apis");//從設備中刪除一個應用 driver.ShakeDevice();//模擬設備搖晃 driver.CloseApp();//關閉應用 driver.LaunchApp();//根據服務關鍵字 (desired capabilities) 啟動會話 (session) 。請注意這必須在設定 autoLaunch=false 關鍵字時才能生效。這不是用於啟動指定的 app/activities driver.ResetApp();//應用重置 driver.GetContexts();//列出所有的可用上下文 driver.GetContext();//列出當前上下文 driver.SetContext("name");//將上下文切換到默認上下文 driver.GetAppStrings();//獲取應用的字符串 driver.KeyEvent(176);//給設備發送一個按鍵事件:keycode driver.GetCurrentActivity();//獲取當前 activity。只能在 Android 上使用 //driver.Pinch(25, 25);//捏屏幕 (雙指往內移動來縮小屏幕) //driver.Zoom(100, 200);//放大屏幕 (雙指往外移動來放大屏幕) driver.PullFile("Library/AddressBook/AddressBook.sqlitedb");//從設備中拉出文件 driver.PushFile("/data/local/tmp/file.txt", "some data for the file");//推送文件到設備中去 driver.FindElement(By.Name("")); driver.FindElementById("id"); driver.FindElementByName("text"); driver.FindElementByXPath("//*[@name='62']");
2) 注意事項:
使用driver.Sendkeys(string str)向文本框輸入內容前,最好先element.Click( )一下,否則某些情況下,輸入的內容會請不掉,文本框提示的內容也會在 輸入的文本前顯示出來。sendkey方法在發送數據之前會清空一下文本框,一般不需要Clear,如前面的情況Clear后仍是存在的,click后正常
- 3. 等待頁面加載策略:
1) 顯性等待:調用selenium的方法, 需要添加WebDriver.Support引用
顯性等待是指在代碼進行下一步操作之前等待某一個條件的發生。最不好的情況是使用Thread.sleep()去設置一段確認的時間去等待。但為什么說最不好呢?因為一個元素的加載時間有長有短,你在設置sleep的時間之前要自己把握長短,太短容易超時,太長浪費時間。selenium webdriver提供了一些方法幫助我們等待正好需要等待的時間
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10)); element = wait.Until<IWebElement>((d) => { return driver.FindElement(By.Id("userName")); });
2) 隱性等待:設置時間不易過長,設置為500或1000即可
隱性等待是指當要查找元素,而這個元素沒有馬上出現時,告訴WebDriver查詢Dom一定時間。默認值是0,但是設置之后,這個時間將在WebDriver對象實例整個生命周期都起作用。
driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(1));
- 4. drive.KeyEvent(int )的使用: 可使用KeyEvent發送鍵盤數據,比如退格,Enter鍵等
driver.KeyEvent(3); //KEYCODE_HOME 按鍵Home 3 driver.KeyEvent(26); //KEYCODE_POWER 電源鍵 26 driver.KeyEvent(67); //KEYCODE_DEL 退格鍵 67 driver.KeyEvent(66); //KEYCODE_ENTER 回車鍵 driver.KeyEvent(122); //KEYCODE_MOVE_HOME 光標移動到開始 driver.KeyEvent(123); //KEYCODE_MOVE_END 光標移動到末尾
-
5. 坐標操作
為防止不同手機分辨率不同帶來的影響,要避免使用固定的坐標,可以用以下方式獲取元素的坐標
double Screen_X = driver.Manage().Window.Size.Width;//獲取手機屏幕寬度 double Screen_Y = driver.Manage().Window.Size.Height;//獲取手機屏幕高度 double startX = element.Location.X; //獲取元素的起點坐標,即元素最左上角點的橫坐標 double startY = element.Location.Y; //獲取元素的起點坐標,即元素最左上角點的縱坐標 double elementWidth = element.Size.Width; //獲取元素的寬度 double elementHight = element.Size.Height; //獲取元素的寬度
在封裝“滑動”、“ TouchAction”等操作時可以用以上方法來獲取坐標進行操作。
示例:分裝兩個元素之間的滑動
IWebElement elmentA = null; IWebElement elmentB = null; int startX = 0, startY = 0, endX = 0, endY = 0; int duration=0,time=0; /// <summary> /// 從元素A的位置滑動到元素B的位置 /// </summary> /// <param name="A">元素A的名稱</param> /// <param name="B">元素B的名稱</param> /// <param name="sDuration">滑動持續時間</param> /// <param name="sTime">滑動次數</param> public void SwipeAToB(string A, string B,string sDuration,string sTime) { startX = elmentA.Location.X + elmentA.Size.Width / 2; //元素A的中心橫坐標 startY = elmentA.Location.Y + elmentA.Size.Height / 2; //元素A的中心縱坐標 endX = elmentB.Location.X + elmentB.Size.Width / 2; //元素B的中心橫坐標 endY = elmentB.Location.Y + elmentB.Size.Height / 2; //元素B的中心縱坐標 duration = string.IsNullOrEmpty(sDuration) ? 1500 : int.Parse(sDuration); //持續時間為空時,默認設置為1500毫秒 time = string.IsNullOrEmpty(sTime) ? 1500 : int.Parse(sTime); //滑動次數為空時,默認設置為滑動1次 for (int i = 0; i < time; i++) { driver.Swipe(startX, startY, endX, endY, duration); } }
注意:element.Loaction和element.Size,每次獲取時都會重新去手機里獲取,為節省時間如果有獲取相同值的,建議儲存成變量。
- 6. 取消重新安裝unlock和setting
注銷如下代碼:
Appium\node_modules\appium\lib\devices\android\android.js
async.series([
this.initJavaVersion.bind(this),
this.initAdb.bind(this),
this.packageAndLaunchActivityFromManifest.bind(this),
this.initUiautomator.bind(this),
this.prepareDevice.bind(this),
this.checkApiLevel.bind(this),
this.pushStrings.bind(this),
this.processFromManifest.bind(this),
this.uninstallApp.bind(this),
this.installAppForTest.bind(this),
this.forwardPort.bind(this),
this.pushAppium.bind(this),
this.initUnicode.bind(this),
// DO NOT push settings app and unlock app
//this.pushSettingsApp.bind(this),
//this.pushUnlock.bind(this),
function (cb) {this.uiautomator.start(cb);}.bind(this),
this.wakeUp.bind(this),
this.unlock.bind(this),
this.getDataDir.bind(this),
this.setupCompressedLayoutHierarchy.bind(this),
this.startAppUnderTest.bind(this),
this.initAutoWebview.bind(this),
this.setActualCapabilities.bind(this)
], function (err) {
