`
shuai1234
  • 浏览: 926667 次
  • 性别: Icon_minigender_1
  • 来自: 山西
社区版块
存档分类
最新评论

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

 
阅读更多

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

 

[html] view plaincopy
 
  1. 打电话<a href="tel:10086" >移动客服</a>  
  2. 发短信<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

 

[javascript] view plaincopy
 
  1. var Phone = function() {  
  2.   
  3. };  
  4. Phone.prototype.call = function (successCallback, failureCallback,number) {  
  5.     cordova.exec(successCallback, failureCallback, "Phone""call", [number]);  
  6. };  
  7.   
  8. window.Phone = new Phone();  


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

 

 

[javascript] view plaincopy
 
  1. successCallback   
  2. failureCallback  

 

 

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

[javascript] view plaincopy
 
  1. number  

做为电话号码
在方法里边调用
phonegap的cordova.exec()

[javascript] view plaincopy
 
  1. cordova.exec(successCallback, failureCallback, "Phone""call", [number]);  


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

 

[java] view plaincopy
 
  1. package com.juhuibao.PhoneGapPlugin;  
  2.   
  3. import java.util.Date;  
  4.   
  5. import org.apache.cordova.api.CallbackContext;  
  6. import org.apache.cordova.api.CordovaPlugin;  
  7. import org.apache.cordova.api.PluginResult;  
  8. import org.json.JSONArray;  
  9. import org.json.JSONException;  
  10. import android.app.Activity;  
  11. import android.content.Intent;  
  12. import android.database.Cursor;  
  13. import android.net.Uri;  
  14. import android.provider.CallLog.Calls;  
  15. import android.telephony.PhoneNumberUtils;  
  16.   
  17. public class Phone extends CordovaPlugin {  
  18.       
  19.     private static final int PHONE_CALL = 0;     // 拨打电话  
  20.     private static final int PHONE_ABORT = 1;     // 挂断电话  
  21.     private Date start_time;  
  22.     private CallbackContext callbackContext;     
  23.     private String phonenumber;  
  24.       
  25.     @Override  
  26.     public boolean  execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {  
  27.         try{  
  28.   
  29.         this.callbackContext = callbackContext;  
  30.           
  31.         if ("call".equals(action)) {  
  32.             this.phonenumber=args.getString(0);  
  33.             this.call(args.getString(0),callbackContext);  
  34.             return true;  
  35.         }  
  36.         if ("abort".equals(action)) {  
  37.            this.abort(callbackContext);  
  38.             return true;  
  39.         }  
  40.         return false;  
  41.         }  
  42.         catch(Exception e){  
  43.             callbackContext.error(e.getMessage());  
  44.         }  
  45.         return false;  
  46.     }  
  47.     //拨打电话  
  48.     private  void call(String phonenumber, CallbackContext callbackContext) {  
  49.   
  50.         if (phonenumber != null && phonenumber.length() > 0) {   
  51.               
  52.             if(PhoneNumberUtils.isGlobalPhoneNumber(phonenumber)){  
  53.              Intent i = new Intent();    
  54.              i.setAction(Intent.ACTION_CALL);   
  55.              i.setData(Uri.parse("tel:"+phonenumber));     
  56.              start_time=new Date();  
  57.              this.cordova.startActivityForResult(this, i,PHONE_CALL);  
  58.                
  59.             }  
  60.             else{  
  61.                 callbackContext.error(phonenumber+"不是有效的电话号码。");  
  62.             }    
  63.         } else {  
  64.             callbackContext.error("电话号码不能为空.");  
  65.         }  
  66.     }  
  67.     //中断电话  
  68.     private void abort(CallbackContext callbackContext) {  
  69.   
  70.     }  
  71.     public void onActivityResult(int requestCode, int resultCode, Intent intent) {  
  72.         Date end_time=new Date();  
  73.         if (resultCode == Activity.RESULT_OK) {  
  74.   
  75.             if (requestCode == PHONE_CALL) {  
  76.   
  77.                 this.callbackContext.error("未知状态");  
  78.             }   
  79.         }  
  80.         else if (resultCode == Activity.RESULT_CANCELED) {  
  81.             try{  
  82.                 if (requestCode == PHONE_CALL) {  
  83.                 long duration=GetLastCallDuration();  
  84.                       
  85.                         PhoneResult result=new PhoneResult();  
  86.   
  87.                         result.setNumber(Phone.this.phonenumber);  
  88.                         result.setStartTime(Phone.this.start_time);  
  89.                         result.setEndTime(end_time);  
  90.                         result.setDuration(duration);  
  91.                         this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, result.toJSONObject()));  
  92.                           
  93.                     }   
  94.             }  
  95.             catch(Exception e){  
  96.                 this.callbackContext.error(e.getMessage());  
  97.             }  
  98.     }  
  99.   
  100.     else {  
  101.         this.callbackContext.error("其他错误!");  
  102.            
  103.     }  
  104.     }  
  105.     long delayTime=0;  
  106.     long timeOut=2000;  
  107.     long GetLastCallDuration() throws InterruptedException{  
  108.         Activity activity = this.cordova.getActivity();  
  109.         Cursor cursor = activity.getContentResolver().query(Calls.CONTENT_URI,   
  110.                 new String[] {Calls.NUMBER,Calls.DATE, Calls.DURATION, Calls.TYPE, Calls.DATE },   
  111.                 "number=?and type=?",   
  112.                 new String[]{this.phonenumber,"2"},   
  113.                 Calls.DEFAULT_SORT_ORDER);  
  114.         activity.startManagingCursor(cursor);  
  115.         boolean hasRecord = cursor.moveToFirst();  
  116.         if (hasRecord) {   
  117.             long endTime=cursor.getLong(cursor.getColumnIndex(Calls.DATE));  
  118.             Date date = new Date(endTime);  
  119.             long duration = cursor.getLong(cursor.getColumnIndex(Calls.DURATION));  
  120.             long dif=this.start_time.getTime()-date.getTime();  
  121.             long second=dif/1000;  
  122.             if(second<2&&second>-2){  
  123.                 return duration;  
  124.             }else{  
  125.                 if(delayTime>=timeOut){  
  126.                     return 0;  
  127.                 }  
  128.                 Thread.sleep(200);  
  129.                 delayTime+=200;  
  130.                 return GetLastCallDuration();  
  131.             }  
  132.         }else{  
  133.             if(delayTime>=timeOut){  
  134.                 return 0;  
  135.             }  
  136.             Thread.sleep(200);  
  137.             delayTime+=200;  
  138.             return GetLastCallDuration();  
  139.         }  
  140.     }  
  141.   
  142. }  

 

 

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

 

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

 

[java] view plaincopy
 
  1. if(PhoneNumberUtils.isGlobalPhoneNumber(phonenumber)){  
  2.              Intent i = new Intent();    
  3.              i.setAction(Intent.ACTION_CALL);   
  4.              i.setData(Uri.parse("tel:"+phonenumber));     
  5.              start_time=new Date();  
  6.              this.cordova.startActivityForResult(this, i,PHONE_CALL);  
  7.                
  8.             }  
  9.             else{  
  10.                 callbackContext.error(phonenumber+"不是有效的电话号码。");  
  11.             }    



 

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

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

 

[java] view plaincopy
 
  1. else if (resultCode == Activity.RESULT_CANCELED) {  
  2.             try{  
  3.                 if (requestCode == PHONE_CALL) {  
  4.                 long duration=GetLastCallDuration();  
  5.                       
  6.                         PhoneResult result=new PhoneResult();  
  7.   
  8.                         result.setNumber(Phone.this.phonenumber);  
  9.                         result.setStartTime(Phone.this.start_time);  
  10.                         result.setEndTime(end_time);  
  11.                         result.setDuration(duration);  
  12.                         this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, result.toJSONObject()));  
  13.                           
  14.                     }   
  15.             }  
  16.             catch(Exception e){  
  17.                 this.callbackContext.error(e.getMessage());  
  18.             }  
  19.     }  

 

 

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

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

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

附 PhoneResult.java

 

[java] view plaincopy
 
  1. package com.juhuibao.PhoneGapPlugin;  
  2. import java.text.SimpleDateFormat;  
  3. import java.util.Date;  
  4.   
  5. import org.json.JSONException;  
  6. import org.json.JSONObject;  
  7. public class PhoneResult {  
  8.     private String number = "";           
  9.     private Date startTime;        
  10.     private Date endTime;;       
  11.     private long duration = 0;       
  12.   
  13.       
  14.   
  15.     public JSONObject toJSONObject() throws JSONException {  
  16.   
  17.         SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss:S");  
  18.           
  19.         return new JSONObject(  
  20.                 "{number:" + JSONObject.quote(number) +  
  21.                 ",startTime:" + JSONObject.quote(sdf.format(startTime)) +  
  22.                 ",endTime:" + JSONObject.quote(sdf.format(endTime)) +  
  23.                 ",duration:" + duration + "}");  
  24.     }  
  25.   
  26.   
  27.   
  28.     public String getNumber() {  
  29.         return number;  
  30.     }  
  31.   
  32.   
  33.   
  34.     public void setNumber(String number) {  
  35.         this.number = number;  
  36.     }  
  37.   
  38.   
  39.   
  40.     public Date getStartTime() {  
  41.         return startTime;  
  42.     }  
  43.   
  44.   
  45.   
  46.     public void setStartTime(Date startTime) {  
  47.         this.startTime = startTime;  
  48.     }  
  49.   
  50.   
  51.   
  52.     public Date getEndTime() {  
  53.         return endTime;  
  54.     }  
  55.   
  56.   
  57.   
  58.     public void setEndTime(Date endTime) {  
  59.         this.endTime = endTime;  
  60.     }  
  61.   
  62.   
  63.   
  64.     public long getDuration() {  
  65.         return duration;  
  66.     }  
  67.   
  68.   
  69.   
  70.     public void setDuration(long duration) {  
  71.         this.duration = duration;  
  72.     }  
  73. }  



 

这样native端的代码完成。

 

三、客户端调用

 

[javascript] view plaincopy
 
  1. window.Phone.call(function (obj) { alert(JSON.stringify(obj));  
  2.                           
  3.                     }, function (err) { alert(err); }, "13401100000");  

 

四、配置插件

在config.xml文件中注册插件

 

[html] view plaincopy
 
  1. <plugin name="Phone" value="com.juhuibao.PhoneGapPlugin.Phone"/>  


在AndroidManifest.xml文件中增加权限

 

 

[html] view plaincopy
 
  1. <uses-permission android:name="android.permission.CALL_PHONE" />  
  2. <uses-permission android:name="android.permission.READ_CALL_LOG" />  
  3. <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />   
  4. <uses-permission android:name="android.permission.READ_PHONE_STATE"/>  



 

 

《完》

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics