2018-04-16 13:05:37 qq_22802643 阅读数 1092

小乙先生接到一个特殊的任务,在原生android里面集成cordova。早就耳闻cordoca的大名,但是工作没机会用,索性也没有去学这个东西。今天正好有时间研究研究。废话不多说,下面开始干活:

一、环境搭建

    这里就不讲了,百度一下就知道了,网上很多教程。这里给个链接 cordova中文网 里面有如何搭建环境和创建项目

二、android原生集成cordova(环境 window7 android studio)

   1、先建立一个cordova项目

         cmd步骤为:
             1).cordova create xiaoyi com.xiaoyi xiaoyi
             2).添加Android平台:cordova platform add android 

             3).cordova build android


新建完后的cordova项目

    2、打开platforms/android


这不就一android 项目嘛。CordovaLib不就一module嘛

    2、导入CordovaLib到android

          1、新建一Android项目

          2、导入module

    

复制res/xml资源到android项目。复制java文件到android项目(我这里因为使用了一个cordova,所以会有camera的包)


        3、MainActivity继承CordovaActivity,调用loadUrl方法,便可以asset下面的东西了。如果要访问外部链接 需要配置res/xml/config.xml

        代码在demo里面 



2017-08-25 14:49:30 weixin_38713540 阅读数 1517

         对于网上很多人分享的,原生项目集成cordova进行混合开发,很多人说的都很笼统,刚接触的小白,有时候很容易懵逼。其实集成不同的开发环境,刚开始就一点:从原生进入Cordova和从Cordova返回原生、或者从原生进入ReactNative和ReactNative返回原生。这一点做好了之后后面才是开始写代码,否则都是白瞎。

        首先:你已经有了iOS原生项目(名字:myIOS),搭建cordova开发环境就没必要讲了,这是最基础的。新建一个Cordova项目。(我的项目需要用Ionic所以我直接Cordova和Ionic一起弄得,这个不影响),能够正常使用Cordova项目(名字:myCordova)。

       具体的图文操作可以参考这个作者的博文:http://blog.csdn.net/e20914053/article/details/50170487

        然后有几个注意事项,我在下面提一下:

        myCordova 项目找到platforms/ios/下的CordovaLib、www拷贝到myIOS文件目录下,然后在myIOS项目中add file这两个www(添加文件夹)和CordovaLib.xcodeproj(不要添加文件夹) 添加完成之后。再在platforms/ios/项目名称 之后找到config.xml 也拷贝过去,千万记得如果你用到很多别的插件的话,一定要烤这个文件,不要拷贝myCordova主目录下的config.xml。因为主目录下的config.xml只包含基本的。你添加在插件在这个里面并没有。如果添加错了就会导致:你集成之后,一直提示你添加的插件不存在,请在config.xml核实一下。然后还有个文件夹需要platforms/ios/myCordova下面有一个生成的插件文件夹Plugins这个文件夹需要添加在老项目里面。这几个文件是需要认真查看的。否则是会报错的

2019-09-09 14:52:45 qq_35213765 阅读数 90

首先你得要有一个cordova的项目,因为太多太多的东西需要从那里复制粘贴了。。。
那我们就开始吧!

第一步:打开你的android原生项目;

第二步:将Cordova项目的Cordovalib导入安卓项目,并在app的build.gradle中添加依赖;

图1


第三步:在main文件夹下创建assets文件夹,然后将Cordova项目的H5端代码(即WWW文件夹)拷贝到assets里面;
在这里插入图片描述
第四步:在res下创建一个新的文件夹xml,然后将Cordova项目中res\xml\config.xml拷贝进去;
在这里插入图片描述
第五步:创建一个包,包名为com.test.MyPlugin,然后把Cordova项目对应目录下的MyPlugin.java文件复制粘贴进去;

第六步:再把cordova项目中的白名单的包复制粘贴过来;
在这里插入图片描述
第七步:开始测试:

7.1 新建类TestCordovaActivity,继承CordovaActivity,加载index.html

public class TestCordova extends CordovaActivity {

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // enable Cordova apps to be started in the background
    Bundle extras = getIntent().getExtras();
    if (extras != null
            && extras.getBoolean("cdvStartInBackground", false)) {
        moveTaskToBack(true);
    }

    // Set by <content src="index.html" /> in config.xml
    // 加载H5首页
    loadUrl(launchUrl);
}
}

7.2 在MainActivity添加按钮,点击跳转至TestCordovaActivity页面

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Button button = findViewById(R.id.button);
    button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent(MainActivity.this,
                    TestCordova.class);
            MainActivity.this.startActivity(intent);
        }
    });
}
}

在这里插入图片描述
上面是我看别人做的,顺便写下来让自己印象深刻一点,不过借鉴过来的时候并不能一次性就跑通,还是有些问题的,下面就写出我觉得需要注意的点:

第一点:白名单一点要按照上面我写的那样,包名一致,类名一致;

第二点:config.xml文件中一定要注意value的值!!!
在这里插入图片描述
value的值就是MyPlugin.java文件的路径!!!

第三点:就是注意cordova.plugin.js文件中的内容!
在这里插入图片描述

2016-07-21 18:10:52 u013491677 阅读数 22626

一 安装node.js

下载地址:https://nodejs.org/en/

安装完成后,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
  • 2.查看已安装的插件列表

    备注:懒得进行以上步骤的朋友,可以点击以下链接直接下载,对于开发使用没有影响。

    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"/>

</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();
        }
    }
}
2019-02-28 19:14:00 weixin_30411819 阅读数 41

iOS-Cordova集成开发,已有项目集成cordova

项目组准备开发一个APP,要求Android和iOS端页面完全一致,除了一个页面跟业务相关的不同,其他界面基本一致,因此,萌生一个想法,关于webAPP的想法。于是乎苦逼的我们开始调研可行性以及整体的方案流程。为了达到除了业务数据页面用web,其他页面全是原生APP的作用。其中,关于业务的web页面需要调用原生的相机,相册,地理位置,麦克风,扬声器,扫描二维码等一系列功能,这就涉及到js与原生交互的问题了。
我们iOS端提出的方案是直接用WebView或者用WKWebView嵌套在实现web与原生的交互就可以了,不过安卓同事说安卓因为其平台多样性和特殊性这个就不兼容而且可行性交差,列出了集中方案,最终确定双方都用Cordova实现该功能。然后,开始了iOS端关于Cordova的学习之路(如果已经集成,请下翻到5节)

1 Cordova简介

Cordova前身是phonegap,而PhoneGap是Nitobi软件公司2008年推出的一个框架,旨在弥补web和iOS之间的不足,使得web和iPhone SDK之间的交互更容易。后来又加入了Android SDK 和BlackBerry SDK,再然后又陆续加入了更多的平台。但是在2011年,Nitobi公司被Adobe收购,PhoneGap也被提交到Apache Incubator。由于Adobe现在拥有PhoneGap商标,PhoneGap v2.0版产品就更名为Apache Cordova。

据说Cordova是Nitobi团队当时坐落的街道名称,用此名来纪念Nitobi团队的贡献。Apache Cordova是从PhoneGap中抽出的核心代码,是驱动PhoneGap的核心引擎。

1.2 Cordova的工程结构

有下图可以看出,关于Cordova的工程结构以及与Native API之间的关系:


 
cordova机构图.png

由上图可以看出,其实Cordova的使用分为上面几个框架结构,在Native与web之间交互。

2 Cordova安装

2.1 准备工作

因为本人从事iOS工作,所以只阐述在Mac端安装Cordova的步骤及解释,至于windows下安装Cordova的步骤,这里不再赘述。
(1)首先,你要有一台Mac电脑,如果没有,那么,你就把这篇文章关了吧,看了也没什么用。
(2)然后你需要安装xcode,当然,你要开发,这一点必不可少。
(3)你需要申请证书,然后在xcode中设置配置文件开发者账号...(可后面再做)。
(4)好了,你可以开始安装Cordova了。

2.1 安装Node.js

要安装Cordova,需要先安装Node.js在Node.js官网,上下载并安装,下载好以后,一步一步点击下去就好。如果你实在不会,可以参考文章Mac下安装Node.js

 
nodejs.png

 

2.2 安装git

git一般不用安装,osx和linux都自带git,可以在命令行输入git --version检查一下。如果没有git,需要到git官网下载安装一个git客户端。

 
git.png

 

2.3 使用node.js的依赖包管理工具npm来进行cordova安装

接下来,在终端输入命令:

 sudo npm install -g cordova

 

 

过程可能稍微有点枯燥和漫长,请耐心等待,其实需要输入的安装命令只有npm install -g cordova,之所以输入sodu,是因为有点Mac直接输入前一句代码是安装不起的,安装效果如下图:
 
install.png

为了写文章所以第二次安装,第一次安装的效果不记得了,哈哈~

3 创建你的第一个Cordova工程

3.1 新建项目

继续,打开终端,cmd切换目录到工作目录下,输入以下命令,同样,可能需要点时间来完成

 cordova create Demo com.cordova.demo.hello HelloWorld 

参数描述:
Demo(参数是必填):将为你的项目生成一个Demo目录 www子目录是应用程序的主页,以及各种资源(css,js,img),遵循共同的web开发文件命名规范。这些资源将存储在设备上的本地文件系统,而不是远程服务。config.xml文件包含重要的需要生成和分发应用程序的元数据。
com.cordova.demo.hello(参数可选):App ID,如果不填写这个参数,第三个参数就要省略,默认值是 io.cordova.hellocordova,但建议你填写一个适当的值。
HelloWorld(参数可选):应用程序的项目名 这个参数的默认值是 HelloCordova,但建议你填写一个适当的值。

3.2 添加平台支持

所有后续命令在项目的目录中进行,可在该项目任何子目录中,cmd切换到项目目录下:

  cd Demo

在构建项目之前,你需要指定一组目标平台。你能够运行这些命令取决于您的机器是否支持每一个SDK,合理是否已安装SDK。在MAC上运行命令:

 cordova platform add ios

如果需要查看Cordova支持平台以及已经添加的平台,终端输入命令:

  cordova platforms ls

3.3 添加插件

根据项目具体功能需要,可添加插件以简单方便调用原生接口,如需添加插件,可以去Cordova插件库搜索需要的插件:

 cordova plugin add com.phonegap.plugins.barcodescanner
 cordova plugin add org.apache.cordova.file-transfer
 cordova plugin ls

并非所有的插件都是全平台支持的,有些可能只支持安卓,也有的可能同时支持安卓和iOS,所以在多平台开发时,请慎重选择插件。个人建议,可自定义插件类,可参考官网Cordova自定义插件

3.4 迭代项目

 // 在工程目录下运行下面的命令来构建项目:
  cordova build  
 // 或者,指定生成iOS平台代码项目:
  cordova platform add iosiOS_Cordova

4 运行项目

4.1 打开工程

步骤走完第三章,那么,一个简单的Cordova项目就已经搭建完成了,现在,我们运行下我们工程。打开目录下

/Users/****/Desktop/测试cordova/Demo/platforms/ios

为了避免引起混淆,建议移除掉下图中两个文件/文件夹引用(应用哦):

 
config.png

4.2 EventsCordova生命周期事件

生命周期函数释义
deviceready 当Cordova加载完成会触发
pause 当应用程序进入到后台时触发
resume 应用程序从后台进入到前台会触发

4.3 Plugin APIs自定义Plugin方法

这里看Api就可以的。

到此cordova环境的搭建集成基本完成了。有一些项目已经完成了突然要集成cordova,该怎么办呢?往下看。

5 将Cordova本地相关文件copy到已存的项目中

5.1 找到相关路径,复制文件到工程目录

首先,进入到上一篇文章中创建的Cordova项目的路径中/Users/****/Desktop/Demo/platforms/ios,找到下面需要copy的4个文件夹( CordovaLib ,cordova, www, platform_www

 

)copy到工程项目的根路径中,如下
 
copy.png

5.2 拷贝对应的config.xml文件到对应的工程目录

然后将下面图中所示的config.xml文件copy到需要的iOS项目路径文件夹内,如图:


 
config

6 配置相关参数

6.1 打开工程,进入工程TARGETS -> Build Phases 下,然后入下图所示,点击①中的按键,创建New Run Script Phase,②为创建的Run Script:
 
image
6.2 将下图示意图中,①原名称Run Script修改为Copy www directory;然后讲②中的选项去掉,最后将下面的代码字段复制到③中:
NODEJS_PATH=/usr/local/bin; NVM_NODE_PATH=~/.nvm/versions/node/`nvm version 2>/dev/null`/bin; N_NODE_PATH=`find /usr/local/n/versions/node/* -maxdepth 0 -type d 2>/dev/null | tail -1`/bin; XCODE_NODE_PATH=`xcode-select --print-path`/usr/share/xcs/Node/bin; PATH=$NODEJS_PATH:$NVM_NODE_PATH:$N_NODE_PATH:$XCODE_NODE_PATH:$PATH && node cordova/lib/copy-www-build-step.js

 

 

如图:
 
image
6.3 在工程 Build Settings -> Other Linker Flags 中添加-ObjC -all_load
 
image
6.4 Add Files to ... -> CordovaLib.xcodeproj
 
image
6.5 Add Files to ... -> config.xml
 
image
6.6 Add Files to ... -> www文件夹
 
image
6.7 Schemes按照下图配置,然后编译一次程序(command+R),最后导入下面两项

Build Phases -> Target Dependencies -> CordovaLib

 

Build Phases -> Link Binary With Libraries -> libCordova.a
 
image
6.8 Schemes按照下图配置,将"ViewController.h" 文件改为:
#import <Cordova/CDVViewController.h>
#import <Cordova/CDVCommandDelegateImpl.h>
#import <Cordova/CDVCommandQueue.h>
@interface ViewController : CDVViewController
@end

至此,Cordova嵌入已存的开发项目就已经完成了,运行程序就可看到工程中www文件目录下,index.html文件中的网页信息了。只需要将该文件内容,改为公司需要的网页内容即可。具体交互以及自定义插件,将在后面文章中介绍。

自定义插件

7.1 在config.xml文件中加入下面代码:

<feature name="YourPluginName"> 
    <param name="ios-package" value="Plugin" /> 
    <param name="onload" value="true" /> 
</feature>
 
config.png
3.1 创建一个Plugin类,实现下面的方法

下面介绍一个简单的web端调用原生手机相机以及选择相册图片并返回web显示的自定义插件调用:

  • (1)YanSYPlugin.h 的实现
#import <Cordova/CDVPlugin.h>
@interface Plugin : CDVPlugin
{
    UIImagePickerController *_imagePickerController;//相机
}
- (void)myMethod:(CDVInvokedUrlCommand *)command;
@end
  • (2)YanSYPlugin.m 的实现
#import "Plugin.h"

typedef void(^imgBlock)(NSString *data);
@interface Plugin() <UIImagePickerControllerDelegate, UINavigationControllerDelegate>
@property (copy, nonatomic) imgBlock myBlock;
@end

@implementation Plugin

- (void)myMethod:(CDVInvokedUrlCommand *)command {
    [self.commandDelegate runInBackground:^{
        NSString* myarg = [command.arguments objectAtIndex:0];
        if (myarg !=nil) {
            [self switchMethodWithName:myarg andCommand:(CDVInvokedUrlCommand*)command];
        }else{
            return ;
        }
    }];
}

// 根据方法选择判断调用具体内容
- (void)switchMethodWithName:(NSString *)name andCommand:(CDVInvokedUrlCommand*)command{
    _imagePickerController = [[UIImagePickerController alloc] init];
    _imagePickerController.delegate = self;
    _imagePickerController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
    _imagePickerController.allowsEditing = YES;
    __block CDVPluginResult* pluginResult = nil;
    NSString * standbyJSStr = [NSString stringWithFormat:@"%@",@"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAAVCAYAAACt4nWrAAAEDWlDQ1BJQ0MgUHJvZmlsZQAAOI2NVV1oHFUUPrtzZyMkzlNsNIV0qD8NJQ2TVjShtLp/3d02bpZJNtoi6GT27s6Yyc44M7v9oU9FUHwx6psUxL+3gCAo9Q/bPrQvlQol2tQgKD60+INQ6Ium65k7M5lpurHeZe58853vnnvuuWfvBei5qliWkRQBFpquLRcy4nOHj4g9K5CEh6AXBqFXUR0rXalMAjZPC3e1W99Dwntf2dXd/p+tt0YdFSBxH2Kz5qgLiI8B8KdVy3YBevqRHz/qWh72Yui3MUDEL3q44WPXw3M+fo1pZuQs4tOIBVVTaoiXEI/MxfhGDPsxsNZfoE1q66ro5aJim3XdoLFw72H+n23BaIXzbcOnz5mfPoTvYVz7KzUl5+FRxEuqkp9G/Ajia219thzg25abkRE/BpDc3pqvphHvRFys2weqvp+krbWKIX7nhDbzLOItiM8358pTwdirqpPFnMF2xLc1WvLyOwTAibpbmvHHcvttU57y5+XqNZrLe3lE/Pq8eUj2fXKfOe3pfOjzhJYtB/yll5SDFcSDiH+hRkH25+L+sdxKEAMZahrlSX8ukqMOWy/jXW2m6M9LDBc31B9LFuv6gVKg/0Szi3KAr1kGq1GMjU/aLbnq6/lRxc4XfJ98hTargX++DbMJBSiYMIe9Ck1YAxFkKEAG3xbYaKmDDgYyFK0UGYpfoWYXG+fAPPI6tJnNwb7ClP7IyF+D+bjOtCpkhz6CFrIa/I6sFtNl8auFXGMTP34sNwI/JhkgEtmDz14ySfaRcTIBInmKPE32kxyyE2Tv+thKbEVePDfW/byMM1Kmm0XdObS7oGD/MypMXFPXrCwOtoYjyyn7BV29/MZfsVzpLDdRtuIZnbpXzvlf+ev8MvYr/Gqk4H/kV/G3csdazLuyTMPsbFhzd1UabQbjFvDRmcWJxR3zcfHkVw9GfpbJmeev9F08WW8uDkaslwX6avlWGU6NRKz0g/SHtCy9J30o/ca9zX3Kfc19zn3BXQKRO8ud477hLnAfc1/G9mrzGlrfexZ5GLdn6ZZrrEohI2wVHhZywjbhUWEy8icMCGNCUdiBlq3r+xafL549HQ5jH+an+1y+LlYBifuxAvRN/lVVVOlwlCkdVm9NOL5BE4wkQ2SMlDZU97hX86EilU/lUmkQUztTE6mx1EEPh7OmdqBtAvv8HdWpbrJS6tJj3n0CWdM6busNzRV3S9KTYhqvNiqWmuroiKgYhshMjmhTh9ptWhsF7970j/SbMrsPE1suR5z7DMC+P/Hs+y7ijrQAlhyAgccjbhjPygfeBTjzhNqy28EdkUh8C+DU9+z2v/oyeH791OncxHOs5y2AtTc7nb/f73TWPkD/qwBnjX8BoJ98VVBg/m8AAAEFSURBVDgRY/z969//GO9HDAd3f2agNmDKjX9KE4NBDmXasPwDTgcX14sxPP+vg4JBYsQCJmIVkqNu1HCsoUbTYGEJiBBgCE8SZLCw5WTg4CDeLkt7bgYrB24UFx878JXh+MGvcDGW6ctl4BxSGCCDSxpQk2VPwysUw4l3Kik2Q9XS1HAWkCV//vxn2LL2M8Od6z9Q3AfyOnq4oiggwGF5++YvQ4TzA4Yrl75jUSpGkeFMM3re4DAYi10kCjHt3kb9ohbmBqZHN3/B2FSnmdg4GaluKMxAJitn1FwGk6AGzZRXKcrAykId16Obw2RgwsmwYJMcg4omBwOlVniH8jFISbPBPQ0Ay3NHXHSKRhIAAAAASUVORK5CYII="];

    if ([name isEqualToString:@"调用相机"]) {
        [self selectImageFromCameraWithBlock:^(NSString *data) {
            // 因当前转码格式为iOS原生转码,web端无法解析 ,所以百度了一波图片转码成功后复用,若转码格式正确 可直接上传字符串
            // NSString *jsStr = [NSString stringWithFormat:@"data:image/png;base64,%@",data];
            // 使用备用字符串上传
            pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:standbyJSStr];
            [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
        }];
    }else if ([name isEqualToString:@"查看相册"]){
        [self selectImageFromAlbumWithBlock:^(NSString *data) {
            // 因当前转码格式为iOS原生转码,web端无法解析 ,所以百度了一波图片转码成功后复用,若转码格式正确 可直接上传字符串
            // NSString *jsStr = [NSString stringWithFormat:@"data:image/png;base64,%@",data];
            // 使用备用字符串上传
            pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:standbyJSStr];
            [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
        }];
    }else {
        pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"You Are Error"];
        [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
    }
}

#pragma mark 从摄像头获取图片或视频
- (void)selectImageFromCameraWithBlock:(imgBlock)block{
    self.myBlock = block;
    _imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
    //相机类型(拍照、录像...)字符串需要做相应的类型转换
    //视频上传质量
    //UIImagePickerControllerQualityTypeHigh高清
    //UIImagePickerControllerQualityTypeMedium中等质量
    //UIImagePickerControllerQualityTypeLow低质量
    //UIImagePickerControllerQualityType640x480
    _imagePickerController.videoQuality = UIImagePickerControllerQualityTypeHigh;
    //设置摄像头模式(拍照,录制视频)为录像模式
    _imagePickerController.cameraCaptureMode = UIImagePickerControllerCameraCaptureModePhoto;
    [self.viewController presentViewController:_imagePickerController animated:YES completion:nil];
}

#pragma mark 从相册获取图片或视频
- (void)selectImageFromAlbumWithBlock:(imgBlock)block{
    self.myBlock = block;
    _imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
    [self.viewController presentViewController:_imagePickerController animated:YES completion:nil];
}

#pragma mark UIImagePickerControllerDelegate
//该代理方法仅适用于只选取图片时
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(nullable NSDictionary<NSString *,id> *)editingInfo {
    
    NSString *encodedImageStr = [self imageProcessing:image];
    self.myBlock(encodedImageStr);
}

//适用获取所有媒体资源,只需判断资源类型
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info{
    NSString *encodedImageStr = [self imageProcessing:info[UIImagePickerControllerEditedImage]];
    self.myBlock(encodedImageStr);
    [self.viewController dismissViewControllerAnimated:YES completion:nil];
}

// 图像处理 若未下载base64者 可不用查看
- (NSString *)imageProcessing:(UIImage *)proImage{
    // 判断传过来照片的大小进行裁剪
    CGFloat width  = proImage.size.width;
    CGFloat height = proImage.size.height;
    CGSize size;
    if (width>height) {
        size = CGSizeMake(800, 450);
    }else {
        size = CGSizeMake(450, 800);
    }
    // 创建一个bitmap的context
    // 并把它设置成为当前正在使用的context
    UIGraphicsBeginImageContext(size);
    // 绘制改变大小的图片
    [proImage drawInRect:CGRectMake(0,0, size.width, size.height)];
    // 从当前context中创建一个改变大小后的图片
    UIImage * tailoringImage =UIGraphicsGetImageFromCurrentImageContext();
    // 使当前的context出堆栈
    UIGraphicsEndImageContext();
    // 判断图片大小进行压缩
    NSData *imageData = UIImageJPEGRepresentation(tailoringImage,1.0);
    
    NSLog(@"imagedata == %lud,size.width = %f==%f",(unsigned long)imageData.length,tailoringImage.size.width,tailoringImage.size.height);
    
    if (imageData.length>100*1024) {
        if (imageData.length>1024*1024) {     //1M以及以上
            imageData=UIImageJPEGRepresentation(tailoringImage, 0.1);
        }else if (imageData.length>512*1024) {//0.5M-1M
            imageData=UIImageJPEGRepresentation(tailoringImage, 0.3);
        }else if (imageData.length>200*1024) {//0.25M-0.5M
            imageData=UIImageJPEGRepresentation(tailoringImage, 0.7);
        }
    }
    NSLog(@"imagedata == %lud,size.width = %f==%f",(unsigned long)imageData.length,tailoringImage.size.width,tailoringImage.size.height);
   
    // 最后进行 base64 转码
    // NSString * encodedImageStr = [GTMBase64 stringByEncodingData:imageData];
      // 原生转码方法
    NSString * encodedImageStr = [imageData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
    return encodedImageStr;
}
@end
  • (3)编写index.html文件如下
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title></title>
        <script type="text/javascript" src="cordova.js"></script>
        <script type="text/javascript" src="cordova_plugins.js"></script>
        <script type="text/javascript" src="jquery.min.js"></script>
        <script type="text/javascript">
            document.addEventListener("deviceready", yourCallbackFunction, false);
            
            function cameraBTClick(){
                Cordova.exec(successFunction, failFunction, "YanSYPlugin", "myMethod", ["调用相机"]);
            }
        function PhotoAlbumBTClick(){
            Cordova.exec(failFunction, failFunction, "YanSYPlugin", "myMethod", ["查看相册"]);
        }
        
        function failFunction(error){
            alert("error");
            document.getElementById("returnValue").value = img;
        }
        function aaaa(){
            document.getElementById("2").innerHTML = "<img src='data:image/png;base64,"
        }
        
        function successFunction(img){
            document.getElementById("returnValue").value = img;
            document.getElementById("2").innerHTML = "![]("+img+")"
        }
        
            </script>
        
    </head>
    
    <body>
        <p>点击下面按钮调用相机拍照</p>
        <button onclick="cameraBTClick()">调用相机</button>
    </body>
    
    <body>
        <p>点击下面按钮选择相册照片</p>
        <button onclick="PhotoAlbumBTClick()">查看相册</button>
        <button onclick="aaaa()">测试</button>
        <h1>这是回调结果展示区</h1>
        <textarea id ="returnValue" type="value" rows="5" cols="40">
        </textarea>
        
    </body>
    
    <body>/Users/YanSY/Desktop/代码运行示意11.gif
        <p>
        <img id="1" src=“”/>
        </p>
        <p id="2" > </p>
        
    </body>
    
 
</html>

 

 

将以上代码,按步骤写入程序中,可测试调用原生相机,注意,需要在plist文件中添加隐私权限。运行效果示例如下只做到调用原生相机相册。
 
result.gif

到这里基本结束了,需要Demo的点这里.

这样集成Cordova需要依赖cordova的一个工程,下篇文章介绍一种不需要依赖关系的方式,直接导入相关文件使用。



作者:afyylong
链接:https://www.jianshu.com/p/90605320bb28
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

转载于:https://www.cnblogs.com/YangFuShun/p/10452561.html

没有更多推荐了,返回首页