自己动手开发phonegap插件之《phonegap拨打电话插件》

最近采用phonegap做一个APP,需要在应用内实现拨打电话,通话结束后能反馈通话相关状态,查看了一番phonegap官方文档,似乎没有跟电话相关的api,在互联网上也大概搜了一下,好像没找到相关的内容。其实html5是支持直接在网页上拨打电话的,只要加入如下html代码即可:

打电话<a href="tel:10086" >移动客服</a>
发短信<a href="sms:10086" >发短信</a>

但这中方式只能实现拨打电话和发送短信,不能反馈结果,比如我想在应用能实现拨打电话,通话结束后自动保存通话的电话号码、通话时间、时长等,默认的html功能就不能满足了。

 

phonegap官方不提供的功能,我们只有自己通过开发插件了实现了,phonegap官网上有一个phonegap插件开发指导http://docs.phonegap.com/en/2.5.0/guide_plugin-development_index.md.html#Plugin%20Development%20Guide

下面我们通过代码来简单介绍下phonegap插件开发步骤:

一、定义JS插件API

var Phone = function() {

};
Phone.prototype.call = function (successCallback, failureCallback,number) {
    cordova.exec(successCallback, failureCallback, "Phone", "call", [number]);
};

window.Phone = new Phone();

上面的代码我们定义了一个Phone插件,插件有一个call API,我们传入

successCallback 
failureCallback

分别做为电话拨打成功和失败的回调函数
传入

number

做为电话号码

在方法里边调用
phonegap的cordova.exec()

cordova.exec(successCallback, failureCallback, "Phone", "call", [number]);


就是在这个方法里将执行到native端的功能调用
最后我们new一个Phone对象,把他附件到window对象上,方便以后调用。
这样,插件的JS代码完成。
二、native端代码(以android平台为例)
先直接上代码

package com.juhuibao.PhoneGapPlugin;

import java.util.Date;

import org.apache.cordova.api.CallbackContext;
import org.apache.cordova.api.CordovaPlugin;
import org.apache.cordova.api.PluginResult;
import org.json.JSONArray;
import org.json.JSONException;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.provider.CallLog.Calls;
import android.telephony.PhoneNumberUtils;

public class Phone extends CordovaPlugin {
	
	private static final int PHONE_CALL = 0;     // 拨打电话
    private static final int PHONE_ABORT = 1;     // 挂断电话
    private Date start_time;
    private CallbackContext callbackContext;   
    private String phonenumber;
    
	@Override
	public boolean  execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
		try{

		this.callbackContext = callbackContext;
		
		if ("call".equals(action)) {
			this.phonenumber=args.getString(0);
			this.call(args.getString(0),callbackContext);
	        return true;
	    }
	    if ("abort".equals(action)) {
	       this.abort(callbackContext);
	        return true;
	    }
	    return false;
		}
		catch(Exception e){
			callbackContext.error(e.getMessage());
		}
		return false;
	}
	//拨打电话
	private  void call(String phonenumber, CallbackContext callbackContext) {

        if (phonenumber != null && phonenumber.length() > 0) { 
        	
    	    if(PhoneNumberUtils.isGlobalPhoneNumber(phonenumber)){
    	     Intent i = new Intent();  
    	     i.setAction(Intent.ACTION_CALL); 
    	     i.setData(Uri.parse("tel:"+phonenumber));   
    	     start_time=new Date();
    	     this.cordova.startActivityForResult(this, i,PHONE_CALL);
    	     
    	    }
    	    else{
    	    	callbackContext.error(phonenumber+"不是有效的电话号码。");
    	    }  
        } else {
            callbackContext.error("电话号码不能为空.");
        }
    }
	//中断电话
	private void abort(CallbackContext callbackContext) {

    }
	public void onActivityResult(int requestCode, int resultCode, Intent intent) {
		Date end_time=new Date();
		if (resultCode == Activity.RESULT_OK) {

            if (requestCode == PHONE_CALL) {

            	this.callbackContext.error("未知状态");
            } 
		}
		else if (resultCode == Activity.RESULT_CANCELED) {
			try{
				if (requestCode == PHONE_CALL) {
				long duration=GetLastCallDuration();
					
		            	PhoneResult result=new PhoneResult();

		            	result.setNumber(Phone.this.phonenumber);
		            	result.setStartTime(Phone.this.start_time);
		            	result.setEndTime(end_time);
		            	result.setDuration(duration);
		                this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, result.toJSONObject()));
		                
		            } 
			}
			catch(Exception e){
				this.callbackContext.error(e.getMessage());
			}
    }

    else {
    	this.callbackContext.error("其他错误!");
    	 
    }
	}
	long delayTime=0;
	long timeOut=2000;
	long GetLastCallDuration() throws InterruptedException{
		Activity activity = this.cordova.getActivity();
		Cursor cursor = activity.getContentResolver().query(Calls.CONTENT_URI, 
				new String[] {Calls.NUMBER,Calls.DATE, Calls.DURATION, Calls.TYPE, Calls.DATE }, 
				"number=?and type=?", 
				new String[]{this.phonenumber,"2"}, 
				Calls.DEFAULT_SORT_ORDER);
		activity.startManagingCursor(cursor);
		boolean hasRecord = cursor.moveToFirst();
		if (hasRecord) { 
			long endTime=cursor.getLong(cursor.getColumnIndex(Calls.DATE));
			Date date = new Date(endTime);
			long duration = cursor.getLong(cursor.getColumnIndex(Calls.DURATION));
			long dif=this.start_time.getTime()-date.getTime();
			long second=dif/1000;
			if(second<2&&second>-2){
				return duration;
			}else{
				if(delayTime>=timeOut){
					return 0;
				}
				Thread.sleep(200);
				delayTime+=200;
				return GetLastCallDuration();
			}
		}else{
			if(delayTime>=timeOut){
				return 0;
			}
			Thread.sleep(200);
			delayTime+=200;
			return GetLastCallDuration();
		}
	}

}

然后调用具体实现拨打电话功能的方法call方法,在call方法内我们首先判断电话号码合法性,不合法直接调用callbackContext.error("不是有效的电话号码。"),这个方法将触发JS端的error回调函数执行,并传入一个字符串参数,比如以上的failureCallback

如果电话号码合法则弹出呼叫界面,如下代码

if(PhoneNumberUtils.isGlobalPhoneNumber(phonenumber)){
    	     Intent i = new Intent();  
    	     i.setAction(Intent.ACTION_CALL); 
    	     i.setData(Uri.parse("tel:"+phonenumber));   
    	     start_time=new Date();
    	     this.cordova.startActivityForResult(this, i,PHONE_CALL);
    	     
    	    }
    	    else{
    	    	callbackContext.error(phonenumber+"不是有效的电话号码。");
    	    }  

 

在代码中我们通过变量start_time记录开始时间,然后使用this.cordova.startActivityForResult(this, i,PHONE_CALL);启动Activity。

在终止拨号或挂断电话时将执行onActivityResult方法,我们将在此方法内实现通话状态信息的反馈。主要看一下这段代码

else if (resultCode == Activity.RESULT_CANCELED) {
			try{
				if (requestCode == PHONE_CALL) {
				long duration=GetLastCallDuration();
					
		            	PhoneResult result=new PhoneResult();

		            	result.setNumber(Phone.this.phonenumber);
		            	result.setStartTime(Phone.this.start_time);
		            	result.setEndTime(end_time);
		            	result.setDuration(duration);
		                this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, result.toJSONObject()));
		                
		            } 
			}
			catch(Exception e){
				this.callbackContext.error(e.getMessage());
			}
    }

不管电话有没有接通,resultCode总是等于Activity.RESULT_CANCELED

我们通过GetLastCallDuration()方法获得通话时长,原理就是读取通话记录里边的duration字段,由于通话刚结束时通话记录可能还没出现记录,所以我们要反复调用该方法,直到有记录或到超时时间为止。

取得了时长我们通过this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, result.toJSONObject()));把结果反馈给JS端。

附 PhoneResult.java

package com.juhuibao.PhoneGapPlugin;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.json.JSONException;
import org.json.JSONObject;
public class PhoneResult {
	private String number = "";         
    private Date startTime;      
    private Date endTime;;     
    private long duration = 0;     

    

    public JSONObject toJSONObject() throws JSONException {

    	SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss:S");
    	
        return new JSONObject(
                "{number:" + JSONObject.quote(number) +
                ",startTime:" + JSONObject.quote(sdf.format(startTime)) +
                ",endTime:" + JSONObject.quote(sdf.format(endTime)) +
                ",duration:" + duration + "}");
    }



	public String getNumber() {
		return number;
	}



	public void setNumber(String number) {
		this.number = number;
	}



	public Date getStartTime() {
		return startTime;
	}



	public void setStartTime(Date startTime) {
		this.startTime = startTime;
	}



	public Date getEndTime() {
		return endTime;
	}



	public void setEndTime(Date endTime) {
		this.endTime = endTime;
	}



	public long getDuration() {
		return duration;
	}



	public void setDuration(long duration) {
		this.duration = duration;
	}
}

  

这样native端的代码完成。

 

三、客户端调用

window.Phone.call(function (obj) { alert(JSON.stringify(obj));
                        
                    }, function (err) { alert(err); }, "13401100000");

  

四、配置插件

在config.xml文件中注册插件

<plugin name="Phone" value="com.juhuibao.PhoneGapPlugin.Phone"/>

  

在AndroidManifest.xml文件中增加权限

    <uses-permission android:name="android.permission.CALL_PHONE" />
    <uses-permission android:name="android.permission.READ_CALL_LOG" />
    <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" /> 
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>

  

《完》

 


 

posted @ 2013-03-11 20:44  穷丫小子  阅读(310)  评论(0)    收藏  举报