前段时间,我自己部署的个人网站要用到短信发送功能,当时想到的是在网上找个收费的短信群发平台,结果几乎所有的平台都是千元以上起卖,但是我是自己使用不了太多也不想一次性买这么多短信,怎么办呢?于是我又在网上搜索是否有免费的开源平台用于自己搭建,但是几乎在网上没搜索相关的内容,所以我决定自己用php+android搭建平台。
该平台其实就是android端作为短信发送端,php作为短信管理推送服务端。那么android端就需要开发一个短信发送功能的应用,作为一个phper几乎没接触过android开发,所以只有在网上搜,但是都没有适合的、完整的开源应用,那么又只有自己一边学习一边开发了。之前学习过一点安卓开发的基础知识,对安卓应用的结构有一定了解。于是开始我的发送端的开发:
既然是短信发送端,首先得先做短信发送功能(因为是android菜鸟所以要先确定短信功能是否能实现才能考虑后面的问题),在网上搜索不少关于短信发送的代码段,经过修改测试后代码如下:
1 public void sendsms(String tels,String contents) 2 { 3 //String tel = "135******73"; 4 SmsManager smsManager = SmsManager.getDefault(); 5 PendingIntent sentIntent = PendingIntent.getBroadcast(ServicesSMS.this, 0, new Intent(), 0); 6 7 if(contents.length() >= 70) 8 { 9 //将短信分成多条发送 10 List<String> ms = smsManager.divideMessage(contents); 11 12 for(String str : ms ) 13 { 14 smsManager.sendTextMessage(tels, null, str, sentIntent, null); 15 } 16 } 17 else 18 { 19 //单条发送 20 smsManager.sendTextMessage(tels, null, contents, sentIntent, null); 21 } 22 num++;//记录短信发送条数 23 }
发送短信成功了,那么就该考虑获取服务端数据库里的待发送短信数据,那么连接服务器该用什么协议和包呢,因为我是做web的所以使用http协议来实现与服务器通讯获取数据(用的是HttpPost包):
1 Runnable runnable = new Runnable(){ 2 @Override 3 public void run() { 4 // 5 // TODO: http request. 6 // 7 8 while(auto) 9 { 10 if(checkNetworkState())//检查网路是否可用 11 { 12 requestHttp(); 13 try { 14 Thread.sleep(30000);//循环请求服务器,5分钟一次,可以根据需要自行设定 15 } catch (InterruptedException e) { 16 // TODO Auto-generated catch block 17 e.printStackTrace(); 18 } 19 } 20 } 21 22 //handler.postDelayed(requestHttp(), 1000); 23 24 } 25 public void requestHttp() 26 { 27 28 // http地址 29 //String httpUrl = "http://domain/public/api/getsms.php"; 30 String httpUrl = urlpass; 31 if(httpUrl.equals("")) 32 { 33 Toast.makeText(ServicesSMS.this, "url地址异常!", Toast.LENGTH_LONG).show(); 34 try { 35 Thread.sleep(3000); 36 } catch (InterruptedException e) { 37 // TODO Auto-generated catch block 38 e.printStackTrace(); 39 } 40 onDestroy();//停止服务,后面用到 41 } 42 //HttpPost连接对象 43 HttpPost httpRequest = new HttpPost(httpUrl); 44 //使用NameValuePair来保存要传递的Post参数 45 List<NameValuePair> params = new ArrayList<NameValuePair>(); 46 //添加要传递的参数 47 params.add(new BasicNameValuePair("par", "HttpClient_android_Post")); 48 //设置字符集 49 HttpEntity httpentity = null; 50 try { 51 httpentity = new UrlEncodedFormEntity(params, "utf-8"); 52 } catch (UnsupportedEncodingException e) { 53 // TODO Auto-generated catch block 54 e.printStackTrace(); 55 } 56 //请求httpRequest 57 httpRequest.setEntity(httpentity); 58 //取得默认的HttpClient 59 HttpClient httpclient = new DefaultHttpClient(); 60 //取得HttpResponse 61 HttpResponse httpResponse = null; 62 try { 63 httpResponse = httpclient.execute(httpRequest); 64 } catch (ClientProtocolException e) { 65 // TODO Auto-generated catch block 66 e.printStackTrace(); 67 } catch (IOException e) { 68 // TODO Auto-generated catch block 69 e.printStackTrace(); 70 } 71 //Object mTextView; 72 //HttpStatus.SC_OK表示连接成功 73 String strResult = null; 74 if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) 75 { 76 //取得返回的字符串 77 78 try { 79 strResult = EntityUtils.toString(httpResponse.getEntity()); 80 } catch (ParseException e) { 81 // TODO Auto-generated catch block 82 e.printStackTrace(); 83 } catch (IOException e) { 84 // TODO Auto-generated catch block 85 e.printStackTrace(); 86 } 87 System.out.print(strResult); 88 } 89 else 90 { 91 System.out.print("请求错误!"); 92 } 93 Message msg = new Message(); 94 Bundle data = new Bundle(); 95 data.putString("value",strResult);//获取到的数据 96 msg.setData(data); 97 handler.sendMessage(msg); 98 99 //return runnable; 100 } 101 };
获取到服务器的数据后,就是处理分析数据,然后发送了:
1 Handler handler = new Handler(){ 2 @Override 3 public void handleMessage(Message msg) { 4 super.handleMessage(msg); 5 Bundle data = msg.getData(); 6 String val = data.getString("value");//获取的服务器数据 7 8 9 if(!val.equals("{}"))//“{}”代表服务器没有待发送数据,可以自行定义 10 { 11 JSONObject jsonObject = null;//服务器返回的是json数据,所以需要处理 12 try { 13 jsonObject = new JSONObject(val.toString()).getJSONObject("sms"); 14 } catch (JSONException e) { 15 // TODO Auto-generated catch block 16 e.printStackTrace(); 17 } 18 /*{ 19 * \'a\': 20 * {\'b\': 21 * [ 22 * {\'c\':1}, 23 * {\'d\',2} 24 * ] 25 * } 26 * } 27 * 该格式的json数组需要将[]中的转化为JSONArray*/ 28 29 JSONArray jsonArray = null; 30 try { 31 jsonArray = jsonObject.getJSONArray("list"); 32 } catch (JSONException e1) { 33 // TODO Auto-generated catch block 34 e1.printStackTrace(); 35 } 36 for(int i=0;i<jsonArray.length();i++){ 37 //JSONObject jsonObject2 = (JSONObject)jsonArray.opt(i); 38 JSONObject oj = null; 39 try { 40 oj = jsonArray.getJSONObject(i); 41 } catch (JSONException e) { 42 // TODO Auto-generated catch block 43 e.printStackTrace(); 44 } 45 //aa = aa + oj.getString("name")+"|"; 46 try { 47 tel=oj.getString("tel"); 48 } catch (JSONException e) { 49 // TODO Auto-generated catch block 50 e.printStackTrace(); 51 } 52 try { 53 content=oj.getString("content"); 54 } catch (JSONException e) { 55 // TODO Auto-generated catch block 56 e.printStackTrace(); 57 } 58 sendsms(tel,content);//调用前面提到的发送方法 59 } 60 //String State; 61 if(num>0) 62 { 63 Toast.makeText(ServicesSMS.this, "发送成功,共"+num+"条!", Toast.LENGTH_LONG).show(); 64 } 65 } 66 }; 67 };
到这里,一个具有基本的短信群发功能就实现了,实现过程中也遇到一些问题,其中遇到一个关于线程的问题耽误不少时间:含有http协议请求的功能不能放在主线程中(即需要开辟一个activity或service)。开始不晓得这个,在网上搜索了很久才找到原因。虽然实现了基本功能,但是有些地方还不尽人意,比如不能后台运行,不能自定义服务器地址等。所以我添加了后台运行功能和自定义服务器地址功能,手动开始停止程序功能:
在AndroidManifest.xml中添加服务(解决了http请求不能在主线程中的问题)
1 <service android:name=".ServicesSMS" > 2 <intent-filter> 3 <action android:name="android.intent.action.MAIN" /> 4 <category android:name="android.intent.category.LAUNCHER" /> 5 </intent-filter> 6 </service>
将上面实现功能的放到ServicesSMS.java文件中,其详细过程不再赘述,后面有完整源码地址。
最后就是服务器端程序了:
<?php //读取数据库数据,伪代码 //为了加强安全性,可以加入防伪检验功能 $data=getDataFromDataBase(); if($data==\'\') echo \'{}\';//根据自己需要,定义待发送短信为空的表现方式 else echo json_encode($data);
小弟第一次写博客,不足之处请见谅。附安卓源码地址:http://pan.baidu.com/s/1dDrdoRZ