Android項目裏集成Cordova詳解

  1. 一 安裝nodejs
  2. 二 cmd建立Android項目
  3. 三 導入工程 運行一下
  4. 四 調用插件
  5. 五 Android studio環境下將CordovaLib做爲依賴導入
  6. 六 自定義插件
  7. 七 java類中的一些問題
  8. 八 在CordovaActivity中添加原生View組件
  9. 九 在Fragment裏使用CordovaWebView
  10. 十 Fragment攔截返回鍵

一 安裝node.js

下載地址:https://nodejs.org/en/javascript

安裝完成後,cmd執行html

npm install -g cordovajava

npm install -g cordova@4.1.2 ,全局安裝Cordova。

node

注意:可能會有點慢,請耐心等待!android

二 cmd建立Android項目

  • 1.新建一個項目:
    路徑名>cordova create 文件名 包名 工程名
  • 2.添加Android平臺:cordova platform add android

三 導入工程 運行一下

  • 1.導入工程

    web

  • 2.運行一下,若是出現如下界面,恭喜你,Cordova環境集成成功,你能夠開始下一步操做了。
    apache

四 調用插件

  • 1.cmd添加攝像機插件:android路徑名>cordova plugin add cordova-plugin-camera
  • 2.查看已安裝的插件列表

    備註:懶得進行以上步驟的朋友,能夠點擊如下連接直接下載,對於開發使用沒有影響。npm

    1. 基於node.js4.47無插件下載
    2. 基於node.jd4.4.7全插件下載
  • 3.編寫index.html文件瀏覽器

在head里加入:網絡

<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<script type="text/javascript" charset="utf-8" src="cordova.js"></script>
 <script type="text/javascript" charset="utf-8">

            var destinationType;

            document.addEventListener("deviceready",onDeviceReady,false);

            //Cordova加載完成會觸發
            function onDeviceReady() {
                destinationType=navigator.camera.DestinationType;
            }

            //拍照
            function capturePhoto() {
                if(!navigator.camera){
                    alert('camera:')
                }
                //拍照並獲取Base64編碼的圖像(quality : 存儲圖像的質量,範圍是[0,100])
                navigator.camera.getPicture(onPhotoDataSuccess, onFail, { quality: 50,
                                            destinationType: destinationType.DATA_URL }
                                            );
            }

            //拍照成功
            function onPhotoDataSuccess(imageData) {
                console.log(imageData);
                var smallImage = document.getElementById('smallImage');
                smallImage.style.display = 'block';
                smallImage.src = "data:image/jpeg;base64," + imageData;
            }

            //拍照失敗
            function onFail(message) {
                alert('拍照失敗: ' + message);
            }
        </script>
</head>

在body里加入:

<body style="padding-top:50px">
        <button style="font-size:23px;" onclick="capturePhoto();">拍攝照片</button> <br>
        <img style="display:none;width:240px;height:320px;" id="smallImage" src="" />
 </body>

4.調用相機插件:

1.將CordovaLib做爲Library引入到項目中;
2.把示例demo中的src目錄下的org文件夾、assets文件夾下內容、res文件夾下xml文件夾下的config.xml、AndroidManifest.xml中權限服務考到本身項目中。
3.寫代碼:
(1).建立一個activity extends CordovaActivity;
(2).loadUrl(「file:///android_asset/www/index.html」);
(3).將步驟3寫好的index.html考到assets/www/目錄下;
(4).運行到手機上,應該據能夠調用攝像頭功能了。

添加插件一覽:

1.Device(設備)獲取一些設備信息。

cordova plugin add cordova-plugin-device

2.Connection(網絡鏈接)用來判斷網絡鏈接類型(2G、3G、4G、Wifi、無鏈接等)。

cordova plugin add cordova-plugin-network-information

3.Battery(電池)能夠獲取電池狀態信息。

cordova plugin add cordova-plugin-battery-status

4.Accelerometer(加速計)讓應用在三維空間(使用笛卡爾三維座標系統)中決定設備方向。

cordova plugin add cordova-plugin-device-motion

5.Compass(指南針)可讓開發者讀取移動設備的朝向。

cordova plugin add cordova-plugin-device-orientation

6.Geolocation(地理定位)讓應用判斷設備的物理位置。

cordova plugin add cordova-plugin-geolocation

7.Camera(相機)用相機獲取圖像。

cordova plugin add cordova-plugin-camera

8.MediaCapture(媒體捕獲)與Camera API相比,不只能獲取圖像,還能夠錄視頻或者錄音。

cordova plugin add cordova-plugin-media-capture

9.Media(播放/記錄媒體文件)讓應用能記錄或播放媒體文件。用它能夠在手機後臺播放音頻文件或玩桌面視頻遊戲。

cordova plugin add cordova-plugin-media

10.file(文件訪問操做類)提供對設備上的文件進行讀取和寫入的功能支持。

cordova plugin add cordova-plugin-file

11.fileTransfer(文件傳輸)實現文件上傳、下載及共享等功能。

cordova plugin add cordova-plugin-file-transfer

12.VisualNotification(可視化消息提醒)不一樣於js的alert()、confirm()和prompt()方法是同步的。Cordova的alert()、confirm()和prompt()方法是異步的,而且對顯示內容有更大的控制權限。

cordova plugin add cordova-plugin-dialogs

13.HardwareNofifications(硬件消息提醒)讓設備蜂鳴或振動。

cordova plugin add cordova-plugin-vibration

14.Contacts(聯繫人)讀取聯繫人列表並在應用中使用聯繫人數據,或使用應用數據向聯繫人列表中寫新的聯繫人。

cordova plugin add cordova-plugin-contacts

15.Globalization(全球化)容許應用查詢操做系統的當前設置,判斷用戶使用的語言。

cordova plugin add cordova-plugin-globalization

16.Splashscreen(閃屏)用來在Cordova應用啓動時顯示自定義的閃屏。

cordova plugin add cordova-plugin-splashscreen

17.InAppBrowser(內置瀏覽器)容許在在單獨的窗口中加載網頁。例如要嚮應用用戶展現其餘網頁。固然能夠很容易地在應用中加載網頁內容並管理,但有時候須要不一樣的用戶體驗,InAppBrowser加載網頁內容,應用用戶能夠更方便的直接返回到主應用。

cordova plugin add cordova-plugin-inappbrowser

18.Console(調試控制檯)讓程序能夠在控制檯中打印輸出日誌。

cordova plugin add cordova-plugin-console

19.exitApp(退出應用)讓 Android 或者 Windows Phone 8 上的APP關閉退出(iOS系統不支持)

cordova plugin add cordova-plugin-exitapp

20.barcodeScanner(條形碼/二維碼掃描)不只能夠經過攝像頭識別二維碼/條形碼,還能生成二維碼。

cordova plugin add cordova-plugin-barcodescanner

命令一覽:

1.查看全部已經安裝的插件

cordova plugin ls

2.安裝插件(以camera插件爲例)

cordova plugin add cordova-plugin-camera

3.刪除插件(以camera插件爲例)

cordova plugin rm cordova-plugin-camera

4.更新插件

cordova plugin update

五 Android studio環境下將CordovaLib做爲依賴導入

環境:Android Studio 2.2
- 1.將CordovaLib做爲module導入


- 2.添加依賴

六 自定義插件

  • 1.自定義你的java類

1.1.包名,等下會用到。
1.2.集成的父類。
1.3.重寫的方法。
1.4.傳遞的參數。
1.5.action匹配。

  • 2.在config.xml文件中添加配置

2.1.js文件名
2.2.java類路徑名(詳見1.1)

  • 3.在assets/www/plugins文件夾下新建文件夾cordova-plugin-xxxx文件夾,並在此文件夾下新建xxxx.js文件。

3.1.js的文件夾名.文件名
3.2.方法名
3.3.與config.xml文件下一致
3.4.方法名==2(與java文件下action一致)
3.5.成功回調函數
3.6.失敗回調函數 [content,type]是傳遞的參數

  • 4.在cordova_plugins.js中添加必要配置

4.1.file:js路徑名
4.2.id:js的文件夾名.文件名
4.3.html文件中方法名的前綴 在module.exports.metadata中添加
4.5. js的文件夾名
4.6.版本號

  • 5.在index.html中調用
function Toast(){
    navigator.Toast.getTost("Toast測試",0,onSuccess,onError);
    function onSuccess(Data){
        alert(JSON.stringify(Data));
    }
    function onError(Data){
        alert(JSON.stringify(Data));
    }
 }

 

七 java類中的一些問題

 

  • 1.startActivityForResult

    查看CordovaActivty源碼:

    查看CordovaPlugin源碼:

    在webView的CordovaActivity獲取到Result後,會調用cordovaInterface.onActivityResult(requestCode, resultCode, intent)方法通知CordovaPlugin。若是使用cordova.getActivity().startActivityForResult(intent,CORDOVA_SPEEN)方式,並無將CordovaPlugin傳進去,在webView的CordovaActivity獲取到Result後,結果只會返回到的webView的CordovaActivity當中,並不會進行下一步。

  • 2.回調

mCallbackContext.success(JSONObject);
mCallbackContext.error(JSONObject);

 

 

八 在CordovaActivity中添加原生View組件 #

緣由:繼承CordovaActivity的子類中默認只有一個WebView,實際開發中不能知足需求。
解決方案:可使用setContentView設置XML佈局,須要重寫的兩種方法:makewebview 和createviews。(親測經過extends Activity implements CordovaInterface方法實現時,cordova.startActivityForResult不回調,具體緣由尚不明)
- makewebview() : 很重要,它使用R.id.cordovawebview,會定義在XML佈局文件。
- createViews() : 它會默認使用setContentView,想使用本身定義的佈局,須要重寫該方法。

實現功能:在WebView上增長TitleBar。
- 1.佈局文件(R.layout.activity_cordova_title)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="45dip"
        android:background="#25C28B" >

        <ImageButton
            android:id="@+id/cordova_back"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:background="#00FFFFFF"
            android:paddingLeft="10dp"
            android:paddingRight="20dp"
            android:src="@drawable/back" />

        <TextView
            android:id="@+id/cordova_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="原生頭部"
            android:textColor="#FFFFFF"
            android:textSize="20sp" />

        <Button
            android:id="@+id/cordova_close"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_alignParentRight="true"
            android:background="#00FFFFFF"
            android:paddingLeft="10dp"
            android:paddingRight="20dp"
            android:text="關閉"
            android:textColor="#FFFFFF"
            android:textSize="20sp" />
    </RelativeLayout>

       <org.apache.cordova.engine.SystemWebView
        android:id="@+id/cordovaWebView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

 

  • 2.自定義CordovaActivity類(CordovaTitleActivity)

 

參照源碼copy過來的,由於要使用自定義佈局,因此setContentView相關代碼注掉

public class CordovaTitleActivity extends CordovaActivity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_cordova_title);
        loadUrl(launchUrl);

    }

    @Override
    protected CordovaWebView makeWebView() {
        SystemWebView webView = (SystemWebView) findViewByI(R.id.cordov_webView);
        CordovaWebView cordovaWebView = new CordovaWebViewImpl(new SystemWebViewEngine(webView));
        return cordovaWebView;
    }
    @Override
    protected void createViews() {
        //由於要使用自定義佈局,此處setContentView須要注掉
//      appView.getView().setId(100);
//      appView.getView().setLayoutParams(new FrameLayout.LayoutParams(
//              ViewGroup.LayoutParams.MATCH_PARENT,
//              ViewGroup.LayoutParams.MATCH_PARENT));
//      setContentView(appView.getView());

      if (preferences.contains("BackgroundColor")) {
          int backgroundColor = preferences.getInteger("BackgroundColor", Color.BLACK);
          // Background of activity:
          appView.getView().setBackgroundColor(backgroundColor);
      }
      appView.getView().requestFocusFromTouch();
    }

3.使用Cordova須要注意的問題

1. 在Activity的onCreate方法中,loadUrl(launchUrl)調用以後,CordovaLib中的WebView對象appView纔有值,所以使用appView時,必須寫在loadUrl的後面。
2. 在Cordova中,appView是不能直接調用addJavascriptInterface()方法的,在調用該方法以前,須要加上一行代碼: 
   WebView Wv = (WebView) appView.getEngine().getView();
   調用WebView的其餘方法相似。

 

九 在Fragment裏使用CordovaWebView

 

  • 1.Fragment的佈局文件(cordova_fragmrnt.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

     <org.apache.cordova.engine.SystemWebView
        android:id="@+id/cordov_webView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

-2.Fragment

public class MyFragmentNew extends BaseFragment implements CordovaInterface {

    public static MyFragmentNew newInstance() {
        MyFragmentNew fragment = new MyFragmentNew();
        return fragment;
    }

    private String TAG = "MyFragmentNew";

    private CordovaWebView myCordovaWebView;

    private Context mContext;

    // Plugin to call when activity result is received
    protected CordovaPlugin activityResultCallback = null;
    protected boolean activityResultKeepRunning;
    // Keep app running when pause is received. (default = true)
    // If true, then the JavaScript and native code continue to run in the
    // background
    // when another application (activity) is started.
    protected boolean keepRunning = true;

    private final ExecutorService threadPool = Executors.newCachedThreadPool();

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        mContext = inflater.getContext();
        View thisView = inflater.inflate(R.layout.home_pager_fragment_new,
                container, false);
        SystemWebView homeWebView = (SystemWebView) thisView
                .findViewById(R.id.cordov_webView_home);
        ConfigXmlParser parser = new ConfigXmlParser();
        parser.parse(getActivity());// 這裏會解析res/xml/config.xml配置文件
        myCordovaWebView = new CordovaWebViewImpl(new SystemWebViewEngine(
                homeWebView));// 建立一個cordovawebview
        myCordovaWebView.init(new CordovaInterfaceImpl(getActivity()),
                parser.getPluginEntries(), parser.getPreferences());// 初始化
        myCordovaWebView.loadUrl("file:///android_asset/www/index.html");// 加載網頁

        return thisView;
    }

    @Override
    public void startActivityForResult(CordovaPlugin command, Intent intent,
            int requestCode) {
        this.activityResultCallback = command;
        this.activityResultKeepRunning = this.keepRunning;
        // If multitasking turned on, then disable it for activities that return
        if (command != null) {
            this.keepRunning = false;
        }
        // Start activity
        super.startActivityForResult(intent, requestCode);

    }

    @Override
    public void setActivityResultCallback(CordovaPlugin plugin) {
        this.activityResultCallback = plugin;

    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (myCordovaWebView != null) {
            myCordovaWebView.handleDestroy();
        }
    }

    @Override
    public Object onMessage(String id, Object data) {
        return null;
    }

    @Override
    public ExecutorService getThreadPool() {
        return threadPool;
    }

    @Override
    public void requestPermission(CordovaPlugin plugin, int requestCode,
            String permission) {
        // TODO Auto-generated method stub

    }

    @Override
    public void requestPermissions(CordovaPlugin plugin, int requestCode,
            String[] permissions) {
        // TODO Auto-generated method stub

    }

    @Override
    public boolean hasPermission(String permission) {
        // TODO Auto-generated method stub
        return false;
    }

}
  • 3.須要在Fragment所在的Activity中重寫onActivityResult()方法,將結果通知給自定義插件
public static CordovaPlugin mCordovaPlugin;

    /**
     * 爲了將回調結果回傳給Cordova插件
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        // TODO Auto-generated method stub
        CordovaPlugin cordovaPlugin = this.mCordovaPlugin;
        if(cordovaPlugin != null){
            cordovaPlugin.onActivityResult(requestCode,resultCode,data);
        }
        super.onActivityResult(requestCode, resultCode, data);
    }

 

  • 4.在自定義插件類裏給步驟3裏的mCordovaPlugin賦值

 

public boolean execute(String action, JSONArray args,
        CallbackContext callbackContext) throws JSONException {
        // TODO Auto-generated method stub
        mCallbackContext = callbackContext;

        /*給fragment所在activity裏的mCordovaPlugin賦值,不然fragment所在activity裏onActivityResult()
         * 沒法將結果傳給插件的onActivityResult()。*/
        MyFragmentActivity.mCordovaPlugin = (CordovaPlugin) this;

       // 語音識別
        if ("getSpeechData".equals(action)) {
            RequestData = args.getJSONObject(0);
            Intent intent = new Intent(cordova.getActivity(),
                    SpeechActivity.class);
            intent.putExtra("flag", RequestData.getInt("flag"));
            this.cordova.startActivityForResult((CordovaPlugin) this, intent,
                    CORDOVA_SPEEN);

        return true;
}

 

十 Fragment攔截返回鍵

 

  • 1.原理:利用Fragment的生命週期,在Fragment顯示時通知到Activity,並由Activity保持。當用戶按下物理返回鍵時,首先將back鍵請求交給Fragment處理,若是處理返回true,未處理時返回false。若是Fragment沒有處理則由Activity處理。爲保證Fragment存在嵌套的狀況下也能正常使用,可使用FragmentManager去管理持有的子Fragment,FragmentManager使用遞歸方式處理。

  • 2.定義FragmentBackHandler接口

public interface FragmentBackHandler {
    //用於判斷子fragment是否對返回鍵作處理
    boolean onGoBack();
}

 

  • 3.定義一個BackHandlerHelper工具類,用於實現分發back事件,Fragment和Activity的外理邏輯是同樣,因此二者都須要調用該類的方法。

 

public class BackHandlerHelper {

    /**
     * 將back事件分發給 FragmentManager 中管理的子Fragment,若是該 FragmentManager
     * 中的全部Fragment都 沒有處理back事件,則嘗試 FragmentManager.popBackStack()
     * 
     * @param fragmentManager
     * @return
     */
    public static boolean handleBackPress(FragmentManager fragmentManager) {
        List<Fragment> fragments = fragmentManager.getFragments();

        if (fragments == null)
            return false;

        for (int i = fragments.size() - 1; i >= 0; i--) {
            Fragment child = fragments.get(i);

            if (isFragmentBackHandled(child)) {
                return true;
            }
        }

        if (fragmentManager.getBackStackEntryCount() > 0) {
            fragmentManager.popBackStack();
            return true;
        }
        return false;
    }

    public static boolean handleBackPress(Fragment fragment) {
        return handleBackPress(fragment.getChildFragmentManager());
    }

    public static boolean handleBackPress(FragmentActivity fragmentActivity) {
        return handleBackPress(fragmentActivity.getSupportFragmentManager());
    }

    public static boolean isFragmentBackHandled(Fragment fragment) {
        return fragment != null
                && fragment.isVisible()
                && fragment.getUserVisibleHint() // for ViewPager
                && fragment instanceof FragmentBackHandler
                && ((FragmentBackHandler) fragment).onGoBack();

    }
}
  • 3.在Fragment裏實現FragmentBackHandler接口
public class MyFragmentNew extends BaseFragment implements FragmentBackHandler{

    @Override
    public boolean onGoBack() {
        if(myCordovaWebView.canGoBack()){
            myCordovaWebView.getEngine().goBack();
            return true;
        }
        //return BackHandlerHelper.handleBackPress(this);
        //當確認沒有子Fragmnt時能夠直接return false
        return false;
    }
}

 

  • 4.在宿主Activity覆蓋onBackPressed方法

 

public class MyActivity extends FragmentActivity {
    //.....
    @Override
    public void onBackPressed() {
        //子Fragment沒有作攔截處理
        if (!BackHandlerHelper.handleBackPress(this)) {
            super.onBackPressed();
        }
    }
}
相關文章
相關標籤/搜索