Phonegap插件

时间:2016-06-27 16:07:03

标签: android cordova android-intent alarmmanager android-broadcastreceiver

我正在创建一个Phonegap插件,除其他外,它允许我设置闹钟。我对如何做到这一点的理解如下:

  • 设置操作系统可用于“回拨”应用程序的待处理意图PI
  • 在plugin.xml文件中声明该意图
  • 发出警报
  • 等待操作系统使用PI拨回应用程序。

为此,这里是我写的代码:

  • plugin.xml 文件

    <config-file target="res/xml/config.xml" parent="/*">
    <feature name="Pall">
      <param name="android-package" value="com.example.Plugin"/>
    </feature>
    </config-file>
    
    <config-file target="AndroidManifest.xml" parent="/*">
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <receiver android:name="com.example.plugin.ServiceAlarm" 
     android:enabled="true" android:exported="true" >
     <intent-filter>
       <action android:name="com.example.plugin.ServiceAlarm" />
       <category android:name="android.intent.category.DEFAULT" />
     </intent-filter>
    </receiver>
    </config-file>
    

扩展广播接收器类 - 文件ServiceAlarm.java

import org.apache.cordova.CordovaWebView;
import android.content.Context;
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.widget.Toast;

 public class ServiceAlarm extends BroadcastReceiver
 {

  @Override
  public void onReceive(Context context, Intent intent)
  {
   Toast.makeText(context, msg, Toast.LENGTH_LONG).show();  
   //in a real world app one would do a whole lot more here      
  }
 }

定义插件 - 文件plugin.java

package com.example.plugin;
//various imports
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import ...

 public class Plugin extends CordovaPlugin 
 {
  private Context context;

  @Override
  public void initialize(CordovaInterface cordova, CordovaWebView webView) 
  {
   super.initialize(cordova, webView);
   this.context = cordova.getActivity().getApplicationContext();
  }

  public void makeToast(String msg)
  {
   Toast.makeText(this.context, msg, Toast.LENGTH_LONG).show();      
  }

  private boolean setAlarm(final CallbackContext cbc,Context ctxt,JSONArray data)
  {
   try
   {    
    makeToast("Setting alarm");

    Intent intent = new Intent(ctxt,ServiceAlarm.class);
    intent.setAction("com.example.plugin.ServiceAlarm");

    PendingIntent pendingIntent =  
    PendingIntent.getBroadcast(ctxt,1,intent,PendingIntent.FLAG_ONE_SHOT);
    AlarmManager alarmManager =    
    (AlarmManager)ctxt.getSystemService(Context.ALARM_SERVICE);
    alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 
    SystemClock.elapsedRealtime() + 10000,pendingIntent);
    makeToast("Alarm Set");
    cbc.success("Set!");
    return true;
    } catch(Exception e)
    {
     cbc.error("Failed!");
     return false;
    } 
  } 

跨越JS桥接的Catch方法调用:

@Override
public boolean execute(String action, JSONArray data, CallbackContext cbc)  
throws JSONException 
{
 Context ctxt = this.context;
 try
 {   
  switch(action)
  {
    case "setalarm":return setAlarm(cbc,ctxt,data);
    default:cbc.error(action + " is not known");return false;       
  }   
 }
 catch (Exception e)
 {
  cbc.error(e.getMessage() + "xx");
  return false;   
 }  
}

}

定义Cordova JS桥。文件plugin.js:

var exec = require('cordova/exec');
var plugin = 
{
 setalarm:function (scbk, ecbk) {exec(scbk, ecbk, "Plugin", "setalarm", 
 []);}
};

module.exports = plugin;

完成所有这些后,我使用jquery-mobile-starter模板在Phonegap CLI中创建了一个Phonegap项目:

phonegap create /path/to/project --template jquery-mobile-starter

然后我添加了插件:

phonegap plugin add /path/to/plugin

然后我修改了init中的app.js方法:

function init() 
{
 alert('Init');
 try
 { 
  alert('setting alarm');
  plugin.setalarm(success,failure);
  alert('alarm set');
 } catch(e){alert('error' + e.message);}
}


function success(msg){alert(msg);}
function failure(msg){alert('Error ' + msg);}

据我所知,我已完成以下所有工作:

  • 创建了一个插件
  • 从此插件中暴露出一个方法,在设置后10秒触发警报
  • 创建广播接收器以处理由OS发送的警报事件
  • 声明了在app清单文件中处理此类事件的意图
  • 创建了一个使用此插件的应用
  • 从应用的init方法设置闹钟

该应用程序正确遵守,并在启动时启动我编码的所有各种诊断吐司。但是,从不响应实际的警报事件。

显然,我在这里做错了或者误解了系统如何处理警报。对于任何能够让我走上正轨的人,我都是最有责任的。

+++++++++++++

  

自发布此问题以来,我发现如果我动态注册广播接收器,事情就会按预期工作。

  final String SOME_ACTION = "com.example.plugin.ServiceAlarm";
  IntentFilter intentFilter = new IntentFilter(SOME_ACTION);
  ServiceAlarm mReceiver = new ServiceAlarm(this.context);
  ctxt.registerReceiver(mReceiver, intentFilter);
  Intent intent = new Intent(SOME_ACTION);

这里的明显区别是,不是将ServiceAlarm 传递给Intent构造函数,而是传递ServiceAlarm对象本身的实例。

事实上,这是非常令人欣慰的,但它留下了一个问题 - 我遇到了许多以“其他方式”做事的例子,即我原来的方式。它们是错误的还是我的代码中某处出现错误 - 例如config.xml文件中的Receiver声明。

我希望这里有人能够发现这个问题。

1 个答案:

答案 0 :(得分:0)

问题必须在plugin.xml中。 接收者必须是应用的孩子。可以通过将接收器移动到 应用程序

来分离配置文件来解决此问题:

<config-file target="AndroidManifest.xml" parent="/*/application">
    <receiver android:name="com.example.plugin.ServiceAlarm" >
        <intent-filter>
            <action android:name="com.example.plugin.ServiceAlarm" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
    </receiver>
</config-file>