datePicker 插件在 Phonegap 2.0 中不起作用

Posted

技术标签:

【中文标题】datePicker 插件在 Phonegap 2.0 中不起作用【英文标题】:datePicker plugin not working in Phonegap 2.0 【发布时间】:2012-07-31 09:23:43 【问题描述】:

升级到Phonegap 2.0 后,datePicker 插件不起作用。错误是: 未捕获的类型错误:无法读取未定义的属性“datePicker”。

错误发生在 javascript 代码上: window.plugins.datePicker.show(...

DatePicker js 文件:

/**
* Phonegap DatePicker Plugin Copyright (c) Greg Allen 2011 MIT Licensed
* Reused and ported to android plugin by Daniel van 't Oever
*/
if (typeof cordova !== "undefined") 
/**
 * Constructor
 */
function DatePicker() 
    this._callback;


/**
 * show - true to show the ad, false to hide the ad
 */
DatePicker.prototype.show = function(options, cb) 
    if (options.date) 
        options.date = (options.date.getMonth() + 1) + "/" + (options.date.getDate()) + "/" + (options.date.getFullYear()) + "/"
                + (options.date.getHours()) + "/" + (options.date.getMinutes());
    
    var defaults = 
        mode : '',
        date : '',
        allowOldDates : true
    ;

    for ( var key in defaults) 
        if (typeof options[key] !== "undefined")
            defaults[key] = options[key];
    
    this._callback = cb;

    return cordova.exec(cb, failureCallback, 'DatePickerPlugin', defaults.mode, new Array(defaults));
;

DatePicker.prototype._dateSelected = function(date) 
    var d = new Date(parseFloat(date) * 1000);
    if (this._callback)
        this._callback(d);
;

function failureCallback(err) 
    console.log("datePickerPlugin.js failed: " + err);


cordova.addConstructor(function() debugger;
    if (!window.plugins) 
        window.plugins = ;
    
    window.plugins.datePicker = new DatePicker();
);
;

DatePicker 插件 java 文件:

    /**
 * 
 */
package com.phonegap.plugin;

import java.util.Calendar;
import java.util.Date;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.app.DatePickerDialog;
import android.app.DatePickerDialog.OnDateSetListener;
import android.app.TimePickerDialog;
import android.app.TimePickerDialog.OnTimeSetListener;
import android.util.Log;
import android.widget.DatePicker;
import android.widget.TimePicker;


import org.apache.cordova.DroidGap;
import org.apache.cordova.api.Plugin;
import org.apache.cordova.api.PluginResult;

/**
 * @author ng4e
 * @author Daniel van 't Oever
 * 
 *         Rewrote plugin so it it similar to the ios datepicker plugin and it
 *         accepts prefilled dates and time
 */
public class DatePickerPlugin extends Plugin 

    private static final String ACTION_DATE = "date";
    private static final String ACTION_TIME = "time";
    private final String pluginName = "DatePickerPlugin";

    /*
     * (non-Javadoc)
     * 
     * @see com.phonegap.api.Plugin#execute(java.lang.String,
     * org.json.JSONArray, java.lang.String)
     */
    @Override
    public PluginResult execute(final String action, final JSONArray data, final String callBackId) 
        Log.d(pluginName, "DatePicker called with options: " + data);
        PluginResult result = null;

        this.show(data, callBackId);
        result = new PluginResult(PluginResult.Status.NO_RESULT);
        result.setKeepCallback(true);

        return result;
    

    public synchronized void show(final JSONArray data, final String callBackId) 
        final DatePickerPlugin datePickerPlugin = this;
        @SuppressWarnings("deprecation")
        final DroidGap currentCtx = (DroidGap) ctx.getContext();
        final Calendar c = Calendar.getInstance();
        final Runnable runnable;

        String action = "date";

        /*
         * Parse information from data parameter and where possible, override
         * above date fields
         */
        int month = -1, day = -1, year = -1, hour = -1, min = -1;
        try 
            JSONObject obj = data.getJSONObject(0);
            action = obj.getString("mode");

            String optionDate = obj.getString("date");

            String[] datePart = optionDate.split("/");
            month = Integer.parseInt(datePart[0]);
            day = Integer.parseInt(datePart[1]);
            year = Integer.parseInt(datePart[2]);
            hour = Integer.parseInt(datePart[3]);
            min = Integer.parseInt(datePart[4]);

            /* currently not handled in Android */
            // boolean optionAllowOldDates = obj.getBoolean("allowOldDates");

         catch (JSONException e) 
            e.printStackTrace();
        

        // By default initialize these fields to 'now'
        final int mYear = year == -1 ? c.get(Calendar.YEAR) : year;
        final int mMonth = month == -1 ? c.get(Calendar.MONTH) : month - 1;
        final int mDay = day == -1 ? c.get(Calendar.DAY_OF_MONTH) : day;
        final int mHour = hour == -1 ? c.get(Calendar.HOUR_OF_DAY) : hour;
        final int mMinutes = min == -1 ? c.get(Calendar.MINUTE) : min;

        if (ACTION_TIME.equalsIgnoreCase(action)) 
            runnable = new Runnable() 
                public void run() 
                    final TimeSetListener timeSetListener = new TimeSetListener(datePickerPlugin, callBackId);
                    final TimePickerDialog timeDialog = new TimePickerDialog(currentCtx, timeSetListener, mHour,
                            mMinutes, true);
                    timeDialog.show();
                
            ;

         else if (ACTION_DATE.equalsIgnoreCase(action)) 
            runnable = new Runnable() 
                public void run() 
                    final DateSetListener dateSetListener = new DateSetListener(datePickerPlugin, callBackId);
                    final DatePickerDialog dateDialog = new DatePickerDialog(currentCtx, dateSetListener, mYear,
                            mMonth, mDay);
                    dateDialog.show();
                
            ;

         else 
            Log.d(pluginName, "Unknown action. Only 'date' or 'time' are valid actions");
            return;
        

        //((Activity) ctx).runOnUiThread(runnable);
    

    private final class DateSetListener implements OnDateSetListener 
        private final DatePickerPlugin datePickerPlugin;
        private final String callBackId;

        private DateSetListener(DatePickerPlugin datePickerPlugin, String callBackId) 
            this.datePickerPlugin = datePickerPlugin;
            this.callBackId = callBackId;
        

        /**
         * Return a string containing the date in the format YYYY/MM/DD
         */
        public void onDateSet(final DatePicker view, final int year, final int monthOfYear, final int dayOfMonth) 
            String returnDate = year + "/" + (monthOfYear + 1) + "/" + dayOfMonth;
            datePickerPlugin.success(new PluginResult(PluginResult.Status.OK, returnDate), callBackId);

        
    

    private final class TimeSetListener implements OnTimeSetListener 
        private final DatePickerPlugin datePickerPlugin;
        private final String callBackId;

        private TimeSetListener(DatePickerPlugin datePickerPlugin, String callBackId) 
            this.datePickerPlugin = datePickerPlugin;
            this.callBackId = callBackId;
        

        /**
         * Return the current date with the time modified as it was set in the
         * time picker.
         */
        public void onTimeSet(final TimePicker view, final int hourOfDay, final int minute) 
            /*Date date = new Date();
            date.setHours(hourOfDay);
            date.setMinutes(minute);*/
            Calendar today = Calendar.getInstance();
            today.set(Calendar.HOUR_OF_DAY, hourOfDay);
            today.set(Calendar.MINUTE, minute);
            Date date = today.getTime();

            datePickerPlugin.success(new PluginResult(PluginResult.Status.OK, date.toString()), callBackId);

        
    


在我花时间在 google 上之后,我做了以下更改: 替换

    cordova.addConstructor(function() debugger;
    if (!window.plugins) 
        window.plugins = ;
    
    window.plugins.datePicker = new DatePicker();
    );

window.datePicker = new DatePicker();

更新调用它的js代码

window.datePicker.show(...

现在我仍然可以获取 datePicker 对象,但出现了这个新错误:

Uncaught TypeError: Object # has no method 'exec'

DatePicker.prototype.show = function(options, cb) 
    ...
    return cordova.exec(cb, failureCallback, 'DatePickerPlugin', defaults.mode, new  Array(defaults));
)

感谢您的帮助!

【问题讨论】:

【参考方案1】:

http://docs.phonegap.com/en/2.0.0/guide_plugin-development_android_index.md.html#Developing%20a%20Plugin%20on%20Android

检查后发现:

常见的陷阱

插件可以访问 CordovaInterface 对象。此对象有权访问运行应用程序的 Android 活动。这是启动新的 Android Intent 所需的上下文。 CordovaInterface 允许插件为结果启动 Activity,并为 Intent 返回应用程序时设置回调插件。这很重要,因为 Intents 系统是 Android 在进程之间进行通信的方式。

插件无法像过去那样直接访问上下文。旧版 ctx 成员已弃用,并将在 2.0 发布六个月后删除。 ctx 的所有方法都存在于 Context 上,因此 getContext() 和 getActivity() 都能够返回所需的正确对象。

避免使用 webView.loadUrl() 调用 JavaScript。我们有一个回调服务器的原因是为了让 JavaScript 执行是线程安全的,并且 loadUrl 显式中断 UI 线程,并可能影响插件的可用性。

这是我的解决方法:

在 DatePickerPlugin.java 中

import android.content.Context;
....

public synchronized void show(final JSONArray data, final String callBackId) 
     final DatePickerPlugin datePickerPlugin = this;
     final DroidGap currentCtx = (DroidGap) ctx.getContext();
     final Calendar c = Calendar.getInstance();
.....

换行:

final DroidGap currentCtx = (DroidGap) ctx.getContext();

作者:

final Context currentCtx = cordova.getActivity();

查找:

ctx.runOnUiThread(runnable);

替换为:

cordova.getActivity().runOnUiThread(runnable);

这在我的模拟器 4.0.3 和 phonegap 2.0 中运行良好

【讨论】:

【参考方案2】:

将输入字段设置为键入“日期”会打开本地日期选择器。超级简单的方法。

【讨论】:

【参考方案3】:

window.plugins 已在 PhoneGap 2.0 中删除。尝试从https://github.com/phonegap/phonegap-plugins下载最新版本的插件。

【讨论】:

以上是关于datePicker 插件在 Phonegap 2.0 中不起作用的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Phonegap 2.9 在 config.xml 中声明插件

phonegap 2.2 + jQuery + Mapkit 插件

Phonegap 2.8.1 iOS 分析插件

PhoneGap/Cordova 2.2.0 Facebook 插件在 IOS FB.init 上失败

android phonegap 下载器插件 2.2

Phonegap 在前 2 次加载时构建 Facebook 插件异常