国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android用webView包裝WebAPP方法

2019-10-22 18:15:40
字體:
來源:轉載
供稿:網友

前言 Android webView 兼容體驗真的差到了極點!!

前一陣子,老板要將 WebAPP 放到 Android 和 iOS 里面,而我因為以前做過安卓,所以這方面就由我來打包,原理是很簡單的,就是打開 APP 的時候用 webView 加載網站的網址,這樣服務器一次更新,就能更新微信版, iOS 版和 Android 版;

首先我要說一句,如果你的 WebAPP 里面有文件上傳,并且想要完全兼容,那么就別用原生的 WebAPP, 后面我會寫一個關于 crossWalk 的博客,不過在此之前,我先記錄下我所經歷的一些坑,我的工具使用的是 Android studio;

創建一個項目,這個我就不說了,網上很多教程;

首先在 app/src/main/AndroidManifest.xml 里添加權限:

注意本文代碼中的"..."都代表省略的代碼

<manifest ...>  <uses-permission android:name="android.permission.INTERNET" />  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>  <application      ...  </application></manifest>
  • 第一個是允許訪問網絡連接;
  • 第二個是允許程序寫入外部存儲,如SD卡上寫文件;
  • 第三個是允許應用程序從外部存儲讀取;

再是 app/src/main/res/layout/activity_main.xml 添加:

<WebView    android:id="@+id/local_webview"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:visibility="gone" />

MainActivety.java:

private WebView webview;//...protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.activity_main);  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {    WebView.setWebContentsDebuggingEnabled(true);  }  webview = findViewById(R.id.local_webview);  WebSettings settings = webview.getSettings();  loading = findViewById(R.id.loadView);  settings.setJavaScriptEnabled(true);//必須  settings.setCacheMode(WebSettings.LOAD_DEFAULT);//關閉webview中緩存  settings.setRenderPriority(WebSettings.RenderPriority.HIGH);//提高渲染的優先級  settings.setUseWideViewPort(true);//WebView是否支持HTML的“viewport”標簽或者使用wide viewport。  settings.setAllowContentAccess(true);//是否允許在WebView中訪問內容URL  settings.setBuiltInZoomControls(true);//是否使用其內置的變焦機制  settings.setJavaScriptCanOpenWindowsAutomatically(true);//是否允許自動打開彈窗  settings.setDomStorageEnabled(true);//是否開啟DOM存儲API權限  webview.loadUrl("http://www.baidu.com");  webview.setWebChromeClient(new WebChromeClient() {    @Override    public void onProgressChanged(WebView view, int newProgress) {      Log.d("加載", "on page progress changed and progress is " + newProgress);      //...    }  }    webview.setWebViewClient(new WebViewClient() {    @Override    public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {      super.onReceivedError(view, errorCode, description, failingUrl);          // 加載網頁失敗時處理 如:      view.loadDataWithBaseURL(null,        "<span>頁面加載失敗,請確認網絡是否連接</span>",        "text/html",        "utf-8",        null);    }    @Override    public void onPageFinished(WebView view, String url) {      if (!webview.getSettings().getLoadsImagesAutomatically()) {        webview.getSettings().setLoadsImagesAutomatically(true);      }      Log.d("加載", "end ");    }  });}

這是一個比較簡單的 webView 例子,這里有幾點需要說下:

關于WebSettings:

1.1 需要運行 js 的網頁都需要此設置:setJavaScriptEnabled

1.2 關于setCacheMode,盡量不要設置 LOAD_CACHE_ONLY 該值,設置這個值會在 webkit 類型瀏覽器對短時間內的 ajax 訪問產生Provisional headers are shown問題;

1.3 關于 AllowFileAccess 一般默認值就好,都開了會有安全上的問題;

1.4 WebSettings 的設置內容很多,如果想看更多的話可以進行搜索;

1.5 暫未發現其他問題,待定;

setWebChromeClient 和 setWebViewClient:

2.1 這2個都是 webView 的配置屬性,不過在功能上有所區分:

WebViewClient幫助WebView處理各種通知、請求事件的

WebChromeClient是輔助WebView處理Javascript的對話框,網站圖標,網站title,加載進度等;

js 里面使用 alert 和 confirm 需要在WebChromeClient里面進行修改,提供對話框;

2.2 關于onPageFinished:

如果你的路由里面是異步加載的,如resolve => require(['./routers/XXX'], resolve),那么就要注意,在每進入異步加載的頁面后,都會觸發此函數,所以如果你需要在頁面加載后只執行一次的代碼的話,就放在 setWebChromeClient 的 onProgressChanged 里進行判斷進度是否為100時再執行;

webview.loadUrl():

3.1 這里的加載地址可以有2種,1是 webview.loadUrl("file:///android_asset/index.html"); 訪問本地文件,2是webview.loadUrl("http://www.baidu.com");訪問網絡文件;

各有其優點:若訪問網絡文件,更新服務器內容即可使用最新的功能;而訪問本地資源的話,加載的速度會快一點,而且即使斷網也可以看到默認的東西;

剛剛有說到,進入 APP 的快慢問題,這里我是調用了一個加載的動畫來完成的:

我這邊選擇的動畫時這個:點擊查看

而在 Android studio 里調用插件的方式十分簡單:

打開根目錄下的 build.gradle,在 allprojects 的 repositories 里添加:

maven { url "https://jitpack.io"}

然后打開 app/build.gradle,在 dependencies 里添加:

compile 'com.github.zzz40500:android-shapeLoadingView:1.0.3.2'

這時候先 build 項目,再在 src/main/res/layout/activity_main.xml 里添加代碼:

<android.support.constraint.ConstraintLayout >  <com.mingle.widget.LoadingView    android:id="@+id/loadView"    android:layout_width="fill_parent"    android:layout_height="fill_parent" />  ...</android.support.constraint.ConstraintLayout>

這時候可以,這樣 loading 動畫就添加好了,后面只需要在 Java 代碼里顯示和隱藏就行了;

最關鍵的html:input[type="file"]問題,這個問題才是最大的問題,先說好
如果你的webApp不需要上傳文件或者不在意Android 4.2-4.4 版本的話,可以用該方法
MainActivity.java:
先創建變量

public static final int INPUT_FILE_REQUEST_CODE = 1;  private ValueCallback<Uri> mUploadMessage;  private final static int FILECHOOSER_RESULTCODE = 2;  private ValueCallback<Uri[]> mFilePathCallback;  private String mCameraPhotoPath;

在setWebChromeClient里添加代碼:

public void openFileChooser(ValueCallback uploadMsg, String acceptType) {        Log.d("選擇", "3.0+");        mUploadMessage = uploadMsg;        Intent i = new Intent(Intent.ACTION_GET_CONTENT);        i.addCategory(Intent.CATEGORY_OPENABLE);        i.setType("image/*");        MainActivity.this.startActivityForResult(            Intent.createChooser(i, "Image Chooser"),            FILECHOOSER_RESULTCODE);      }      //Android 5.0      public boolean onShowFileChooser(          WebView webView, ValueCallback<Uri[]> filePathCallback,          WebChromeClient.FileChooserParams fileChooserParams) {        Log.d("選擇", "5.0+");        if (mFilePathCallback != null) {          mFilePathCallback.onReceiveValue(null);        }        mFilePathCallback = filePathCallback;        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);        if (takePictureIntent.resolveActivity(getPackageManager()) != null) {          // Create the File where the photo should go          File photoFile = null;          try {            //設置MediaStore.EXTRA_OUTPUT路徑,相機拍照寫入的全路徑            photoFile = createImageFile();            takePictureIntent.putExtra("PhotoPath", mCameraPhotoPath);          } catch (Exception ex) {            // Error occurred while creating the File            Log.e("WebViewSetting", "Unable to create Image File", ex);          }          // Continue only if the File was successfully created          if (photoFile != null) {            mCameraPhotoPath = "file:" + photoFile.getAbsolutePath();            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,                Uri.fromFile(photoFile));            System.out.println(mCameraPhotoPath);          } else {            takePictureIntent = null;          }        }        Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);        contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);        contentSelectionIntent.setType("image/*");        Intent[] intentArray;        if (takePictureIntent != null) {          intentArray = new Intent[]{takePictureIntent};          System.out.println(takePictureIntent);        } else {          intentArray = new Intent[0];        }        Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);        chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);        chooserIntent.putExtra(Intent.EXTRA_TITLE, "Image Chooser");        chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);        startActivityForResult(chooserIntent, INPUT_FILE_REQUEST_CODE);        return true;      }      // For Android 3.0+      public void openFileChooser(ValueCallback<Uri> uploadMsg) {        Log.d("選擇", "3.0+");        mUploadMessage = uploadMsg;        Intent i = new Intent(Intent.ACTION_GET_CONTENT);        i.addCategory(Intent.CATEGORY_OPENABLE);        i.setType("image/*");        MainActivity.this.startActivityForResult(Intent.createChooser(i, "Image Chooser"), FILECHOOSER_RESULTCODE);      }      //For Android 4.1      public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {        Log.d("選擇", "4+");        mUploadMessage = uploadMsg;        Intent i = new Intent(Intent.ACTION_GET_CONTENT);        i.addCategory(Intent.CATEGORY_OPENABLE);        i.setType("image/*");        MainActivity.this.startActivityForResult(Intent.createChooser(i, "Image Chooser"), MainActivity.FILECHOOSER_RESULTCODE);      }

在主類中添加:

@SuppressLint("SdCardPath")  private File createImageFile() {    File file=new File(Environment.getExternalStorageDirectory()+"/","tmp.png");    mCameraPhotoPath=file.getAbsolutePath();    if(!file.exists())    {      try {        file.createNewFile();      } catch (IOException e) {        e.printStackTrace();      }    }    return file;  }   @Override    public void onActivityResult(int requestCode, int resultCode, Intent data) {      Log.d("result", "show");      if (requestCode == FILECHOOSER_RESULTCODE) {        if (null == mUploadMessage) return;        Uri result = data == null || resultCode != RESULT_OK ? null            : data.getData();        if (result != null) {          String imagePath = ImageFilePath.getPath(this, result);          if (!TextUtils.isEmpty(imagePath)) {            result = Uri.parse("file:///" + imagePath);          }        }        mUploadMessage.onReceiveValue(result);        mUploadMessage = null;      } else if (requestCode == INPUT_FILE_REQUEST_CODE && mFilePathCallback != null) {        // 5.0的回調        Uri[] results = null;          // Check that the response is a good one        if (resultCode == Activity.RESULT_OK) {          if (data == null && !TextUtils.isEmpty(data.getDataString())) {            // If there is not data, then we may have taken a photo            if (mCameraPhotoPath != null) {              results = new Uri[]{Uri.parse(mCameraPhotoPath)};            }          } else {            String dataString = data.getDataString();            if (dataString != null) {              results = new Uri[]{Uri.parse(dataString)};            }          }        }            mFilePathCallback.onReceiveValue(results);        mFilePathCallback = null;      } else {        super.onActivityResult(requestCode, resultCode, data);        return;      }    }

這里還需要一個 ImageFilePath 類文件,我將他放在 GitHub 里面了,后面我會附上鏈接:

至于 Android 4.2-4.4 會有問題是因為這個:點擊查看

ps:需要FQ

而如果你是 native 開發者的話也比較容易解決,就是在點擊時直接用 js 調用 Java 就行了,如果不是的話,一般都需要其他框架或者插件的支持;

我所碰到的問題基本就是這些,如果有錯誤和疏漏之處還請指出,謝謝;

GitHub:https://github.com/Grewer/android-casing-webapp


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 信宜市| 宜兴市| 全州县| 琼结县| 乌鲁木齐市| 剑阁县| 个旧市| 孝感市| 雷州市| 宿迁市| 太白县| 台东县| 闽清县| 合川市| 伽师县| 察隅县| 乌鲁木齐县| 全南县| 赞皇县| 洛扎县| 永泰县| 台湾省| 蕲春县| 长治县| 河池市| 定州市| 康定县| 湟中县| 潞城市| 永济市| 蒙山县| 广元市| 日土县| 武乡县| 定结县| 瑞昌市| 盱眙县| 奎屯市| 嘉兴市| 武鸣县| 彩票|