整合營銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          企業(yè)級(jí)UI自動(dòng)化平臺(tái)—添加腳本

          企業(yè)級(jí)UI自動(dòng)化平臺(tái)—添加腳本

          前章節(jié)我們講了部門部門管理,項(xiàng)目管理,這節(jié)我們繼續(xù)實(shí)現(xiàn)添加腳本。

          那么關(guān)聯(lián)關(guān)系就是,在部門對應(yīng)的項(xiàng)目中添加多個(gè)腳本。實(shí)現(xiàn)這個(gè)模塊我們需要完成三步操作。

          1:完成數(shù)據(jù)表的創(chuàng)建及與部門表和項(xiàng)目表之間的關(guān)聯(lián)關(guān)系

          2:完成前端界面布局

          3:完成對應(yīng)后端接口的開發(fā)

          首先完成第一步,數(shù)據(jù)表的創(chuàng)建,既然是添加腳本,那么我們能夠想到的字段就有:

          腳本名稱,上傳的圖片名稱,操作的類型(點(diǎn)擊、滑動(dòng)、校驗(yàn)...),執(zhí)行的步驟,操作類型的次數(shù),生成腳本的類型。

          對應(yīng)如下:

          ui自動(dòng)化平臺(tái)添加腳本管理模塊:

          SET NAMES utf8;

          SET FOREIGN_KEY_CHECKS=0;

          DROP TABLE IF EXISTS `script_images`;

          CREATE TABLE `script_images` (

          `id` int(11) NOT NULL AUTO_INCREMENT,

          `script_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,

          `image_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,

          `action_type` enum('click','assert','exist') CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,

          `step_number` int(11) NULL DEFAULT NULL,

          `ftp_path` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,

          `department_id` int(11) NULL DEFAULT NULL,

          `project_id` int(11) NULL DEFAULT NULL,

          `repeatCount` int(11) NULL DEFAULT NULL,

          `select_type` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,

          PRIMARY KEY (`id`) USING BTREE,

          INDEX `department_id`(`department_id`) USING BTREE,

          INDEX `project_id`(`project_id`) USING BTREE,

          CONSTRAINT `script_images_ibfk_1` FOREIGN KEY (`department_id`) REFERENCES `department` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,

          CONSTRAINT `script_images_ibfk_2` FOREIGN KEY (`project_id`) REFERENCES `project` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT

          ) ENGINE=InnoDB AUTO_INCREMENT=24 CHARACTER SET=utf8 COLLATE=utf8_general_ci ROW_FORMAT=Compact;

          SET FOREIGN_KEY_CHECKS=1;

          各個(gè)字段看名字對應(yīng)即可。里面定義了部門表和項(xiàng)目表的主外鍵關(guān)聯(lián)關(guān)系,之前章節(jié)詳細(xì)講過,這里不在啰嗦。

          接下來我們實(shí)現(xiàn)前端部分,直接看下前端需要的功能界面。


          完整邏輯為:

          1. 加載用戶界面,界面中包含選擇部門、選擇項(xiàng)目、腳本類型和腳本名稱的輸入項(xiàng),輸入項(xiàng)選擇后,用戶可以上傳圖片。
          2. 上傳圖片后,根據(jù)這張圖片,可以選擇執(zhí)行的動(dòng)作:點(diǎn)擊、校驗(yàn)或是否存在。這三種動(dòng)作分別對應(yīng)到按鈕:“點(diǎn)擊”,“校驗(yàn)”,“是否存在”。
          3. 選擇動(dòng)作后,圖片數(shù)據(jù)被保存,并且動(dòng)作按鈕會(huì)被禁用,直到上傳下一張圖片。
          4. 當(dāng)所有圖片上傳并選擇動(dòng)作完成后,用戶可以點(diǎn)擊“生成測試腳本”按鈕生成腳本。
          5. 在生成腳本的過程中,顯示加載動(dòng)畫和提示,完成后隱藏加載動(dòng)畫,并提示測試腳本已經(jīng)生成。

          在腳本的實(shí)現(xiàn)中使用了Ajax進(jìn)行異步通信,主要進(jìn)行了以下操作:

          • 保存圖片數(shù)據(jù)
          • 上傳圖片
          • 獲取部門信息和對應(yīng)的項(xiàng)目信息
          • 生成測試腳本

          在獲取部門信息和項(xiàng)目信息時(shí),使用GET方法接收服務(wù)器返回的數(shù)據(jù),并更新選擇部門和項(xiàng)目的下拉列表;在保存圖片數(shù)據(jù)、上傳圖片和生成測試腳本時(shí),使用POST方法將數(shù)據(jù)發(fā)送到服務(wù)器。

          完整實(shí)現(xiàn)為:

          <!DOCTYPE html>
          <html lang="en">
          
          <head>
            <meta charset="UTF-8">
            <title>測試腳本生成</title>
          <!--  <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>-->
            <style>
              /*body {*/
              /*  font-family: Arial, sans-serif;*/
              /*  margin: 20px;*/
              /*}*/
          
              h1 {
                text-align: center;
                color: #3c3c44;
                font-weight: bold;
              }
          
              label {
                margin-top: 10px;
                display: block;
                color: #1c1c1d;
              }
          
              select,
              input[type=text],
              input[type=file] {
                width: 100%;
                padding: 12px;
                margin-top: 4px;
                display: inline-block;
                border: 1px solid #ccc;
              }
          
              input[type=file] {
                padding: 3px;
              }
          
              button {
                border: none;
                color: white;
                padding: 14px 28px;
                font-size: 16px;
                cursor: pointer;
                border-radius: 4px;
                margin-top: 16px;
              }
          
              #click_btn {
                background-color: #4CAF50;
              }
          
              #assert_btn {
                background-color: #FF9800;
              }
          
              #generate_script_btn {
                background-color: #2196F3;
              }
            </style>
          </head>
          <body>
          <h1>測試腳本生成</h1>
          <div id="whole-body">
          <label for="select-department">選擇部門:</label>
          <select id="select-department">
            <option value=""> -- 請選擇部門 -- </option>
          </select>
          
          <label for="select-project">選擇項(xiàng)目:</label>
          <select id="select-project">
            <option value=""> -- 請選擇項(xiàng)目 -- </option>
          </select>
          <label for="select_type">腳本類型:</label>
          <select id="select_type">
            <option value=""> -- 請選擇類型 -- </option>
            <option value="1">windows</option>
            <option value="2">unity</option>
            <option value="3">android</option>
          </select>
          <label for="script_name">腳本名稱:</label>
          <input type="text" id="script_name">
          
          <input type="file" id="image_upload">
          
          <br>
          
          <button id="click_btn">點(diǎn)擊</button>
          <button id="assert_btn">校驗(yàn)</button>
          <button id="exist_btn" style="background-color: #9C27B0; color: white; padding: 14px 28px; font-size: 16px; cursor: pointer; border-radius: 4px; margin-top: 16px;">
            是否存在
          </button>
          <button id="generate_script_btn">生成測試腳本</button>
          
          <p id="action_prompt" style="color: red; font-weight: bold; margin-top: 10px;"></p>
          <div id="uploaded_images"></div>
          
          <script>
            var step_number=0;
            var selected_action='';
            // 添加 isImageUploaded 和 isActionPerformed 變量
            var isImageUploaded=false;
            var isActionPerformed=false;
            function save_image_data(image_name, action_type, step_number, script_name,ftp_path, department_id, project_id,repeatCount,select_type) {
              $.ajax({
                url: "/save-image-data", // 您的后端接口
                type: "POST",
                contentType: "application/json",
                data: JSON.stringify({
                  image_name: image_name,
                  action_type: action_type,
                  step_number: step_number,
                  script_name: script_name,
                  // ftp_path: `/bignoxData/bignoxData/software/qa/Mobile/uitest/${script_name}/${image_name}`, // 添加新字段
                  department_id: department_id,
                  project_id: project_id,
                  repeatCount:repeatCount,
                  select_type:select_type,
                  ftp_path: ftp_path, // 添加新字段
                }),
                success: function (res) {
                  console.log("Image data saved successfully");
                  console.log(repeatCount);
                  console.log(select_type);
                  console.log(res); // 添加這一行以查看響應(yīng)內(nèi)容
                },
                error: function (err) {
                  console.error("Image data save failed");
                  console.error(err); // 添加這一行以查看錯(cuò)誤內(nèi)容
                },
              });
            }
            function disableActionButtons() {
              $("#click_btn").attr("disabled", true);
              $("#assert_btn").attr("disabled", true);
            }
          
            function enableActionButtons() {
              $("#click_btn").attr("disabled", false);
              $("#assert_btn").attr("disabled", false);
            }
            disableActionButtons(); // 最初禁用按鈕,直到上傳第一張圖片
            $("#click_btn").on("click", function () {
              selected_action='click';
              var repeatCount=prompt("請輸入點(diǎn)擊次數(shù)", "1");
              repeatCount=parseInt(repeatCount);
              while(isNaN(repeatCount) || repeatCount<1) {
                alert("無效的輸入!至少點(diǎn)擊一次。")
                repeatCount=prompt("請輸入點(diǎn)擊次數(shù)", "1");
                repeatCount=parseInt(repeatCount);
              }
              $("#action_prompt").text("已選擇點(diǎn)擊操作");
          
              if (step_number > 0) {
                var imgCaption=`點(diǎn)擊第${step_number}步。`;
                $("#uploaded_images div:last-child p").text(imgCaption);
              }
          
              disableActionButtons(); // 選擇操作后重新禁用按鈕
              // 修改并添加以下兩行代碼到 #click_btn 的事件處理程序中
              const department_id=$('#select-department').val();
              const project_Id=$('#select-project').val();
              const imageUrl=$(this).attr("data-url");
              const select_type=$('#select_type').val();
              save_image_data(imgFile.name, selected_action, step_number, $("#script_name").val(), imageUrl,department_id, project_Id,repeatCount,select_type);
              isActionPerformed=true; // 將 isActionPerformed 設(shè)置為 true
              //save_image_data(imgFile.name, selected_action, step_number, $("#script_name").val(), `/uploads${res.image_url}`); // 傳遞 ftp_path 參數(shù)
            });
            //新函數(shù)
            $("#image_upload").on("click", function () {
              this.value=null;
            });
            //分割線
            $("#assert_btn").on("click", function () {
              selected_action='assert';
              var repeatCount=1; // 為assert操作設(shè)置repeatCount為1
              $("#action_prompt").text("已選擇校驗(yàn)操作");
          
              if (step_number > 0) {
                var imgCaption=`校驗(yàn)第${step_number}步。`;
                $("#uploaded_images div:last-child p").text(imgCaption);
              }
          
              disableActionButtons(); // 選擇操作后重新禁用按鈕
              // 修改并添加以下兩行代碼到 #click_btn 的事件處理程序中
              const department_id=$('#select-department').val();
              const project_Id=$('#select-project').val();
              const imageUrl=$(this).attr("data-url");
              save_image_data(imgFile.name, selected_action, step_number, $("#script_name").val(), imageUrl, department_id, project_Id,select_type,repeatCount);
              isActionPerformed=true; // 將 isActionPerformed 設(shè)置為 true
              //save_image_data(imgFile.name, selected_action, step_number, $("#script_name").val(), `/uploads${res.image_url}`); // 傳遞 ftp_path 參數(shù)
            });
            $("#exist_btn").on("click", function () {
              selected_action='exist';
              var repeatCount=prompt("請輸入循環(huán)點(diǎn)擊次數(shù)", "1");
              repeatCount=parseInt(repeatCount);
              while(isNaN(repeatCount) || repeatCount<1) {
                alert("無效的輸入!次數(shù)至少為一。")
                repeatCount=prompt("請輸入循環(huán)點(diǎn)擊次數(shù)", "1");
                repeatCount=parseInt(repeatCount);
              }
          
              $("#action_prompt").text("已選擇是否存在操作");
          
              if (step_number > 0) {
                var imgCaption=`是否存在第${step_number}步。`;
                $("#uploaded_images div:last-child p").text(imgCaption);
              }
          
              disableActionButtons();
              const department_id=$('#select-department').val();
              const project_Id=$('#select-project').val();
              const imageUrl=$(this).attr("data-url");
              save_image_data(imgFile.name, selected_action, step_number, $("#script_name").val(), imageUrl, department_id, project_Id,select_type, repeatCount);
              isActionPerformed=true;
            });
            var imgFile; // 將 imgFile 變量移到外面
            $("#image_upload").on("change", function () {
              var fileInput=this;
              imgFile=fileInput.files[0];
              var imgName=imgFile.name;
              var formData=new FormData();
              formData.append("image", imgFile);
              formData.append("script_name", $("#script_name").val());
              formData.append("department_id", $("#select-department").val()); // 新增加這行
              formData.append("project_id", $("#select-project").val());       // 新增加這行
              formData.append("select_type", $("#select_type").val());       // 新增加這行
              step_number++;
          
              $.ajax({
                url: "/upload-image", // 您的后端接口
                type: "POST",
                data: formData,
                processData: false,
                contentType: false,
                success: function (res) {
                  var newImg=document.createElement("img");
                  newImg.src=res.image_url; // 響應(yīng)中的圖片 URL
                  newImg.style.maxWidth="200px";
                  newImg.alt=imgName;
          
                  var imageCaption=document.createElement("p");
          
                  var imageContainer=document.createElement("div");
                  imageContainer.appendChild(newImg);
                  imageContainer.appendChild(imageCaption);
                  $("#uploaded_images").append(imageContainer);
          
                  enableActionButtons(); // 上傳新圖片后啟用點(diǎn)擊和校驗(yàn)按鈕
                  $("#click_btn").attr("data-url", res.image_url);
                  $("#assert_btn").attr("data-url", res.image_url);
                  $("#exist_btn").attr("data-url", res.image_url);
                  enableActionButtons(); // 添加這一行代碼
                  // 在這里設(shè)置 isImageUploaded 為 true
                  isImageUploaded=true;
                },
                error: function (err) {
                  console.error("圖片上傳失敗", err);
                }
              });
            });
            $("#generate_script_btn").on("click", function () {
              if (!isImageUploaded) {
                alert("未上傳任何文件!");
                return;
              }
              if (!isActionPerformed) {
                alert("請先選擇當(dāng)前圖片要執(zhí)行的動(dòng)作!");
                return;
              }
          
              // 添加的部分: 點(diǎn)擊生成后隱藏主頁面,顯示加載動(dòng)畫和提示
              $('#whole-body').hide();
              $('#loading').show();
              // 更新此部分,使用正確的 ID
              console.log("項(xiàng)目ID: " + $("#select-project").val());
              console.log("部門ID: " + $("#select-department").val());
              var postData=JSON.stringify({
                script_name: $("#script_name").val(),
                department_id: $("#select-department").val(),
                project_id: $("#select-project").val(),
                select_type: $("#select_type").val()
              });
              $.ajax({
                url: "/generate-test-script",
                type: "POST",
                contentType: "application/json",
                data: postData,
                success: function (res) {
                  //接收到返回?cái)?shù)據(jù)后先延時(shí)3秒
                  setTimeout(function () {
                    //隱藏加載動(dòng)畫和提示,顯示生成成功提示,并顯示主頁面
                    $('#loading').hide();
                    $('#script_gen_prompt').show(); //顯示生成成功提示
                    alert('測試腳本已生成!');
                    setTimeout(function(){
                      $('#script_gen_prompt').hide();
                      $('#whole-body').show();  //重新顯示主頁面
                    }, 2000);  //2000ms后隱藏成功提示,并重新顯示主界面
                  }, 3000);   // 延時(shí) 3000 ms 顯示生成完成提示
                },
                error: function (err) {
                  setTimeout(function() {
                    $('#loading').hide();
                    alert("生成測試腳本失敗");
                    $('#whole-body').show();  //重新顯示主頁面
                  }, 3000);   // 延時(shí) 3000 ms 顯示失敗提示
                  console.error(err)
                }
              });
            });
            <!-- 在現(xiàn)有的 <script> 標(biāo)簽內(nèi)添加以下代碼 -->
            $(document).ready(function () {
          
              // 獲取部門信息并填充到下拉框
              function loadDepartments() {
                $.get("/get-all-departments", function (data) {
                  var departments=data.departments;
                  $("#select-department").empty();
                  $("#select-department").append("<option value=''> -- 請選擇部門 -- </option>")
                  for (var i=0; i < departments.length; i++) {
                    var option=$("<option>").val(departments[i].id).text(departments[i].name);
                    $("#select-department").append(option);
                  }
                });
              }
          
              loadDepartments();
              $("#select-department, #select-project").on("change", function() {
                if ($("#select-department").val() && $("#select-project").val()) {
                  $("#script_name").prop("disabled", false);
                } else {
                  $("#script_name").prop("disabled", true);
                }
              });
              $("#select-department").on("change", function () {
                var departmentId=$(this).val();
                if (departmentId) {
                  // 發(fā)送請求獲取部門對應(yīng)項(xiàng)目
                  $.get("/get-projects?department_id=" + departmentId, function (data) {
                    var projects=data.projects;
                    $("#select-project").empty();
                    $("#select-project").append("<option value=''> -- 請選擇項(xiàng)目 -- </option>");
                    for (var i=0; i < projects.length; i++) {
                      var option=$("<option>").val(projects[i].id).text(projects[i].name);
                      $("#select-project").append(option);
                    }
                  });
                } else {
                  $("#select-project").empty();
                  $("#select-project").append("<option value=''> -- 請先選擇部門 -- </option>");
                }
              });
          
            })
          </script>
          </div>
          </body>
          <div id="loading" style="display: none; text-align: center;">
            <img src="/uploads/static/Picture/gif/xz.gif" style="width: 200px; height: auto; margin: 0 auto;">
            <p style="margin-top: 20px; font-size: 20px; font-weight: bold;">正在生成腳本...</p>
          </div>
          
          </html>

          對應(yīng)后端生成腳本的邏輯為:

          @app.route('/generate-test-script', methods=['POST'])
          def generate_test_script():
              try:
                  script_name=request.json.get('script_name')
                  script_nameair=request.json.get('script_name') + '.air'
                  department_id=int(request.json.get('department_id'))
                  select_type=request.json.get('select_type')
                  print(select_type)
                  repeatCount=request.json.get('repeatCount')
                  if request.json:
                      project_id=int(request.json.get('project_id'))
                      department_id=int(department_id)
                      project_id=int(project_id)
                      start_package='com.noxgroup.game.android.townsurvivor'
                      # mycursor.execute("SELECT image_name, action_type, step_number, ftp_path FROM script_images WHERE script_name=%s ORDER BY step_number", (script_name, ))
                      # images_data=mycursor.fetchall()
                      # mycursor.execute("SELECT name FROM department WHERE id=%s", (department_id, ))
                      # department_name=mycursor.fetchone()[0]
                      # mycursor.execute("SELECT name FROM project WHERE id=%s and status=1", (project_id, ))
                      # project_name=mycursor.fetchone()[0]
                      sql="SELECT image_name, action_type, step_number, ftp_path,repeatCount FROM script_images WHERE script_name='{}' ORDER BY step_number".format(
                          script_name, )
                      print(sql+'lx')
                      images_data=db.select_data(sql)
                      print('這里出現(xiàn)imagesdata數(shù)據(jù)')
                      print(images_data)
                      sql="SELECT name FROM department WHERE id={}".format(department_id, )
                      department_name=db.select_one_data(sql)[0]
                      sql="SELECT name FROM project WHERE id={} and status=1".format(project_id, )
                      project_name=db.select_one_data(sql)[0]
                      script_folder=os.path.join(os.getcwd(), 'uploads', department_name, project_name, script_nameair)
                      if not os.path.exists(script_folder):
                          os.makedirs(script_folder)
                      with open(os.path.join(script_folder, f"{script_name}.py"), "w") as f:
                          # startapkpath=os.path.join(os.getcwd(), 'uploads', department_name, project_name, "uploadfiles")
                          # try:
                          #     apk_files=glob.glob(f'{startapkpath}/*.apk')
                          #     if not apk_files:
                          #         print(f"No apk files in {startapkpath}")
                          #         return jsonify({"result": "error", "error_message": f"No apk files in {startapkpath}"})
                          #     else:
                          #         apk_file=apk_files[0]
                          # except Exception as e:
                          #     print(e)
                          # a=APK(apk_file)
                          # package=a.get_package()
                          # activity=a.get_main_activity()
                          if project_name=='TownSurvivor':
                              ipconnect='127.0.0.1:{}'.format(config.tsphoneip)
                              print(123)
                          elif project_name=='忍者貓':
                              ipconnect='127.0.0.1:{}'.format(config.maophoneip)
                          elif project_name=='Player':
                              ipconnect='127.0.0.1:{}'.format(config.maophoneip)
                          else:
                              return 'adb erro'
                          print(ipconnect)
                          f.write("from airtest.core.api import *\n")
                          f.write("from airtest.core.settings import Settings as ST \n")
                          f.write("ST.THRESHOLD_STRICT=0.7\n")
                          f.write("ST.THRESHOLD=0.7\n")
                          f.write("auto_setup(__file__)\n")
                          # f.write("import subprocess\n")
                          # # 先構(gòu)造要寫入的子進(jìn)程調(diào)用命令字符串
                          # subprocess_cmd=(
                          #     f"output=subprocess.check_output('adb -s {ipconnect} shell am start -n {package}/{activity}', "
                          #     "shell=True)"
                          # )
                          #
                          # # 然后寫入文件
                          # f.write(subprocess_cmd + "\n")
                          # # f.write("output=subprocess.check_output(f'adb -s {ipconnect} shell am start -n {package}/{activity}', shell=True)\n")
                          # f.write("time.sleep(8)\n")
                          # f.write("print(output.decode())\n")
                          for image_data in images_data:
                              print(image_data)
                              image_name, action_type, step_number, _, repeatCount=image_data  # 接收重復(fù)次數(shù)
                              if action_type=='click':
                                  if int(repeatCount) > 1:
                                      f.write(f"for _ in range({repeatCount}):")  # 添加循環(huán)語句用于重復(fù)點(diǎn)擊
                                      f.write(f"\n    if exists(Template(r'{image_name}')):\n")  # 添加循環(huán)語句用于重復(fù)點(diǎn)擊
                                      f.write(f"        sleep(1.0)\n")  # 添加循環(huán)語句用于重復(fù)點(diǎn)擊
                                      f.write(f"        touch(Template(r'{image_name}'))\n")
                                      f.write(f"    else:\n")
                                      f.write(f"        break\n")
                                  else:
                                      f.write(f"touch(Template(r'{image_name}'))\n")
                                      f.write(f"time.sleep(1)\n")
                              elif action_type=='assert':
                                  f.write(f"assert_exists(Template(r'{image_name}'))\n")
                                  f.write(f"time.sleep(1)\n")
                              elif action_type=='exist':  # 處理新的action
                                  f.write(f"for i in range({repeatCount}):\n")
                                  f.write(f"    if exists(Template(r'{image_name}')):\n")
                                  f.write(f"        touch(Template(r'{image_name}'))\n")
                                  f.write(f"    else:\n")
                                  f.write(f"        break\n")
          
                      # 添加保存腳本邏輯
                      save_generated_script_to_DB(department_name, project_name, script_name,select_type)
                      return jsonify({'result': 'success'}, script_folder)
                  else:
                      return jsonify({'error': 'No script name found.'}), 400
              except Exception as e:
                  print('Error:', e)
                  traceback.print_exc()
                  return jsonify({"result": "error", "error_message": str(e)})
          
          
          

          綜上:添加腳本的功能邏輯開發(fā)完畢。

          下一節(jié):執(zhí)行腳本邏輯開發(fā)。敬請期待

          in10手機(jī)版怎么運(yùn)行安卓APP應(yīng)用?微軟官方并沒有給出正規(guī)的方法,但民間破解組織已經(jīng)成功讓W(xué)in10手機(jī)版安裝安卓APP應(yīng)用。據(jù)外媒報(bào)道,一西班牙開發(fā)者Antonio de la Iglesia寫出了一個(gè)在電腦上使用的神器,只要連接Win10手機(jī),就可以一鍵將安卓APP應(yīng)用裝到Win10手機(jī)上。

          軟件名稱:Win10 Mobile APK Installer(Win10手機(jī)版裝安卓應(yīng)用神器)
          軟件版本:1.1
          軟件大小:10

          能手機(jī)的應(yīng)用開發(fā)也隨著手機(jī)的發(fā)展成為一個(gè)火熱的行業(yè),有著不錯(cuò)的收入。為了方便而有效的進(jìn)行開發(fā)選擇一套合適的開發(fā)模式是十分重要的。智能手機(jī)APP的開發(fā)模式可以分為三類分別是Native APPWeb APP和Hybrid APP開發(fā)模式。


          1三種移動(dòng)APP開發(fā)模式



          1. Native APP


          NativeAPP開發(fā)模式,即本地開發(fā)模式,又稱為傳統(tǒng)型開發(fā)模式。這種開發(fā)模式基于移動(dòng)終端的操作系統(tǒng)進(jìn)行開發(fā),可以良好的利用系統(tǒng)的硬件資源。其缺點(diǎn)也是顯而易見的,其應(yīng)用只能在一種移動(dòng)終端的系統(tǒng)中安裝使用,而且由于APP對硬件的依賴,應(yīng)用升級(jí)會(huì)比較麻煩。


          1.2 Web APP

          Web APP開發(fā)模式基本依靠網(wǎng)絡(luò)技術(shù)實(shí)現(xiàn)。其APP 是一個(gè)針對手機(jī)優(yōu)化后的 Web站點(diǎn),優(yōu)點(diǎn)是實(shí)現(xiàn)了跨平臺(tái),而且對硬件幾乎沒有依賴,開發(fā)周期短。缺點(diǎn)也很明顯,APP 對網(wǎng)絡(luò)的依賴很大,數(shù)據(jù)基本都來自服務(wù)器,因此網(wǎng)絡(luò)狀況會(huì)直接影響用戶體驗(yàn)。在沒有網(wǎng)絡(luò)的情況下,APP的功能基本不能使用。而且APP無法調(diào)用手機(jī)的硬件API功能受到一定的限制。


          1.3 Hybrid APP


          HybridAPP開發(fā)模式即混合開發(fā)模式。這種開發(fā)模式使用第三方的跨平臺(tái)開發(fā)框架,將一種語言開發(fā)出應(yīng)用兼容到不同的移動(dòng)設(shè)備上。這樣開發(fā)者就可以用Java Web技術(shù)或另一種不針對某具體系統(tǒng)的第三方的開發(fā)技術(shù),實(shí)現(xiàn)應(yīng)用的功能。APP同時(shí)具有了跨平臺(tái)性和不錯(cuò)的硬件資源調(diào)用能力。


          2三種開發(fā)模式的環(huán)境配置及APP運(yùn)行



          2.1 Hybrid APP的PhoneGap開發(fā)框架


          Nitobi公司(現(xiàn)在已被Adobe公司收購)推出了基于Web技術(shù)的移動(dòng)解決方案PhoneGap,這一方案在其官網(wǎng)上的定義是“可以使用Web技術(shù)編寫手機(jī)本地應(yīng)用程序的Htm15應(yīng)用程序平臺(tái)”。簡單來說PhoneGap是一套基于Htm15的移動(dòng)應(yīng)用開發(fā)框架6PhoneGap開發(fā)框架成功將Java Web開發(fā)技術(shù)應(yīng)用到了移動(dòng)設(shè)備的開發(fā)上。已經(jīng)具備 Java Web開發(fā)能力的開發(fā)者們可以使用熟知的HTML、CSS和JavaScript來開發(fā)手機(jī)APP。


          PhoneGap 開發(fā)框架支持包括IOS、Android、Windows Phone在內(nèi)的多種手機(jī)平臺(tái)。開發(fā)者通過PhoneGap 提供的插件可以調(diào)用API使用攝像頭聯(lián)系人、地理定位等功能。PhoneGap 的使用是免費(fèi)的它的兼容性強(qiáng)而且開發(fā)成本低。但PhoneGap本身也有不少缺點(diǎn),它的運(yùn)行需要依靠移動(dòng)設(shè)備具有內(nèi)置的瀏覽器引擎WebKit,PhoneGap的APP運(yùn)行速度較慢,硬件調(diào)用能力也不如Native APP。安卓手機(jī)使用 PhoneGap 框架開發(fā)的Hy-bridAPP的基本結(jié)構(gòu)。


          2.2PhoneGapAPP開發(fā)環(huán)境搭建


          開發(fā)PhoneGap APP可以使用Dreamweaver工具來制作Java Web頁面,并使用 PhoneGap Build(PhoneGap的在線編譯云服務(wù))生成安裝包。但如果想測試某一平臺(tái)的硬件功能,就必須配置對應(yīng)的開發(fā)環(huán)境,再進(jìn)行編譯和測試。例如安卓開發(fā)的SDK工具包提供了手機(jī)模擬器,可以在PC機(jī)上進(jìn)行APP測試。

          下面介紹在配置好安卓開發(fā)環(huán)境后,如何使用PhoneGap框架開發(fā)應(yīng)用。首先,下載好 PhoneGap的工具包,打開 Eclipse后,按照創(chuàng)建步驟,新建一個(gè)安卓應(yīng)用項(xiàng)目。復(fù)制cordova-xxxjar 文件到項(xiàng)目中的lib 文件夾下,右擊該jar 文件添加引用。然后在項(xiàng)目的assets 目錄下新建文件,復(fù)制 PhoneGap 工具包內(nèi)的cordovajs 文件到個(gè)文件夾下,并創(chuàng)建Ja-va Web運(yùn)行的級(jí)聯(lián)樣式表,Html文件和其他is 文件。創(chuàng)建完成后的文件結(jié)構(gòu)。


          另外,安卓的應(yīng)用需要依靠Activity啟動(dòng)。要讓Activity啟動(dòng)后,加載html頁面并運(yùn)行JavaScript代碼,需要對Activity進(jìn)行修改。改動(dòng)包括兩步,要將Activity 繼承的類改為 DroidGap,導(dǎo)人需要的cor-dova包。然后將 setContentView(R.layout.activi-ty-main)改為 super.loadUrl(“file://android-asset/www/indexhtml”)其中www是新建的文件夾的名字index.html是該文件夾下的html文件

          編寫好文件夾下的html和is代碼生成apk安裝到安卓手機(jī)上就可以運(yùn)行了。


          2.3NativeAPP的開發(fā)環(huán)境配置及APP運(yùn)行


          對于Native APP發(fā)模式,不同的手機(jī)系統(tǒng)都有套成熟的開發(fā)框架與對應(yīng)的開發(fā)語言”。例如,蘋果手機(jī)的APP需要用Object-C 編寫,AndroidAPP主要用Java開發(fā),而屬于微軟公司的Win-dows Phone應(yīng)用主要使用C#語言開發(fā)。如圖4 所示是安卓手機(jī)的Native APP的基本結(jié)構(gòu)。其中Activity可以理解為活動(dòng)窗口或者是一個(gè)單獨(dú)的頁面,它是與用戶交互的最基本的成像單元。在XMI文件中記錄了手機(jī)頁面的組件信息,Activity啟動(dòng)后加載XML文件顯示頁面。開發(fā)者在 Activity里編寫Java代碼綁定組件,給綁定的組件添加監(jiān)聽事件,在監(jiān)聽事件中實(shí)現(xiàn)功能和API的調(diào)用。


          Android手機(jī)的Native APP開發(fā)環(huán)境配置主要包括兩個(gè)方面,一方面是配置程序設(shè)計(jì)語言的運(yùn)行環(huán)境,需要下載JDK工具包并安裝。另一方面是開發(fā)平臺(tái)的搭建,需要將安卓開發(fā)的ADT插件安裝到Eclipse 開發(fā)平臺(tái)上,并用SDK 工具配置好安卓虛擬機(jī)JDK工具包只需要點(diǎn)擊按照提示即可安裝,配置完環(huán)境變量成后在dos下輸人命令java - version,若顯示 java 的版本則安裝成功。ADT的安裝需要打開 Eclipse,選擇工具欄的安裝新軟件,輸入地址https://dl-ssl.google.com/android/eclipse/,進(jìn)行在線安裝。最后是虛擬機(jī)的創(chuàng)建,要將下載好的SDK包解壓并將路徑配置到 Eclipse 上,隨后在 eclipse 的工具欄打開AVD Manager下載適合自己的手機(jī)系統(tǒng)鏡像并更新到對應(yīng)的平臺(tái)工具。然后打開SDKManager 創(chuàng)建一臺(tái)虛擬機(jī),環(huán)境配置工作就基本完成了。


          2.4WebAPP的環(huán)境配置及APP運(yùn)行


          Web APP開發(fā)模式的環(huán)境搭建主要是服務(wù)器端的環(huán)境搭建,Web APP的使用一般是用手機(jī)自帶的瀏覽器訪問站點(diǎn),不需要下載安裝。這里選擇Java Web的應(yīng)用。Java Web的開發(fā)環(huán)境配置,需要下載Java EE 版的 Eclipse,安裝Tomcat服務(wù)器并配置Java運(yùn)行環(huán)境。僅僅靠 Java Web 技術(shù)開發(fā)出的頁面并不適合手機(jī)顯示,界面往往太大,操作起來也不方便。開發(fā)者可以使用成熟的移動(dòng) Web 開發(fā)框架來解決這個(gè)問題。現(xiàn)在已經(jīng)有了很多優(yōu)秀的移動(dòng) Web開發(fā)框架,例如Sencha TouchjQuery Mobile、DHTMLXTouch等。這些框架對HTML5和CSS3都有不錯(cuò)的支持。用JQuery Mobile界面奈材創(chuàng)建的 Web APP在安卓模擬器上運(yùn)行的效果。


          出處 長春理工大學(xué)學(xué)報(bào)(自然科學(xué)版)

          原標(biāo)題 移動(dòng)APP開發(fā)模式研究

          作者 李莉 張超然 劉丹 李紀(jì)成


          主站蜘蛛池模板: 嫩B人妻精品一区二区三区| 国产一区在线视频| 欧美亚洲精品一区二区| 精品少妇一区二区三区视频| 精品一区狼人国产在线| 日韩美一区二区三区| 日韩精品一区二区三区中文版 | 3d动漫精品啪啪一区二区中 | 国偷自产Av一区二区三区吞精| 国产suv精品一区二区6| 亚洲一区二区精品视频| 一本色道久久综合一区| 无码人妻一区二区三区免费视频| 精品久久久中文字幕一区| 美女AV一区二区三区| 激情爆乳一区二区三区| 国产综合一区二区在线观看| 国产精品日本一区二区不卡视频| 国产AV午夜精品一区二区入口| 无码人妻一区二区三区免费n鬼沢| 高清一区二区三区日本久| 国产综合无码一区二区三区| 精品国产一区二区三区久久 | 亚洲国产精品一区二区成人片国内| 免费萌白酱国产一区二区三区| 亚洲美女视频一区| 国产伦精品一区二区三区免.费| 不卡一区二区在线| 亚洲欧美国产国产一区二区三区| 国产一区内射最近更新| 99久久精品国产高清一区二区| 少妇激情一区二区三区视频| 国内精品视频一区二区八戒| 国产激情精品一区二区三区| 亚洲一区二区三区在线网站| 久久久99精品一区二区| 美女毛片一区二区三区四区| 国产一区二区三区亚洲综合| 亚洲国产精品一区二区成人片国内| 精品少妇ay一区二区三区 | 国内精品视频一区二区三区|