Android專案裡整合Cordova詳解
一 安裝node.js
安裝完成後,cmd執行 npm install -g cordova ,全域性安裝Cordova。
注意:可能會有點慢,請耐心等待!
二 cmd建立Android專案
- 1.新建一個專案:
路徑名>cordova create 檔名 包名 工程名 - 2.新增Android平臺:cordova platform add android
三 匯入工程 執行一下
1.匯入工程
2.執行一下,如果出現以下介面,恭喜你,Cordova環境整合成功,你可以開始下一步操作了。
四 呼叫外掛
- 1.cmd新增攝像機外掛:android路徑名>cordova plugin add cordova-plugin-camera
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"/>
</LinearLayout>
-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();
}
}
}