為方便大家瀏覽,源碼先行奉上
github源碼鏈接 https://github.com/Recycle1/Android-connect-PHP
csdn源碼鏈接 https://download.csdn.net/download/weixin_52263647/87751491
在Android開發(fā)中,經(jīng)常涉及與服務(wù)器端交互的過程,在現(xiàn)在的APP制作中,經(jīng)常利用互聯(lián)網(wǎng)通信,從云端獲取圖片,數(shù)據(jù)等信息,本篇文章將詳細(xì)介紹Android與PHP后端進(jìn)行交互的過程,即利用http進(jìn)行通信的過程。
那熟悉PHP開發(fā)的我們都會(huì)知道PHP頁面的傳參方式有Get和Post,利用此原理我們即可實(shí)現(xiàn)Android端與PHP端的交互,Android端進(jìn)行帶參訪問即進(jìn)行Get方法傳參,對(duì)于大規(guī)模的數(shù)據(jù)如文件的傳輸,利用Post方法,在Android端設(shè)置好相應(yīng)的參數(shù),進(jìn)行大規(guī)模數(shù)據(jù)的傳輸。在之后的講解中,我們將分情況進(jìn)行演示。
在這篇文章中,我們需要準(zhǔn)備的東西有:
- Android手機(jī),這里我調(diào)試使用的是真機(jī),測(cè)試所用的安卓版本為Android 10,當(dāng)前普遍使用的Android 12版本可能會(huì)出現(xiàn)不適配的情況,比如文件讀取和權(quán)限方面,這個(gè)只需稍加調(diào)試即可解決。
- 云服務(wù)器,這里我租用了阿里云的云服務(wù)器,并部署了SSL證書,(當(dāng)然,如果只是android信息交互也可以不使用SSL證書)
那么接下來,我將分情況介紹如何進(jìn)行Android與PHP的交互。
一 Android端
權(quán)限設(shè)置
對(duì)于互聯(lián)網(wǎng)連接方面和文件讀取方面,需要給予一定的權(quán)限,在manifest中設(shè)置
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET" />
文件讀取與寫入(尤其要看一下哦?。。。?/strong>
本地文件讀取與寫入,同時(shí)需要在activity中動(dòng)態(tài)給予權(quán)限。
//初始化權(quán)限
void init_permission(){
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
}
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
}
}
同時(shí),由于在本篇文章中要在手機(jī)內(nèi)存中寫入測(cè)試的文件,因此需要在Mainfest文件中的Application標(biāo)簽下設(shè)置如下權(quán)限,負(fù)責(zé)無法正常讀取路徑和寫入文件。
android:requestLegacyExternalStorage="true"
http網(wǎng)絡(luò)連接設(shè)置(也尤其要看一下哦!?。。?/strong>
在本篇文章中,由于我的云服務(wù)器部署了SSL證書和域名,因此可以利用https進(jìn)行訪問,但是如果沒有SSL證書和域名,我們要利用IP地址進(jìn)行訪問,那需要在Mainfest文件中的Application標(biāo)簽下設(shè)置如下權(quán)限,負(fù)責(zé)無法正常連接到服務(wù)器。
android:usesCleartextTraffic="true"
1. 單條數(shù)據(jù)傳輸(Get方法)
單條數(shù)據(jù)的傳輸,我們?cè)贏ndroid端傳入字符串,服務(wù)器端也會(huì)返回字符串,利用http建立連接。
//主要用于傳輸單條數(shù)據(jù),如字符串等,同時(shí),PHP端也返回單條數(shù)據(jù)
public static String singleData(String path) throws Exception {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");
if (conn.getResponseCode() == 200) {
InputStream inputStream = conn.getInputStream();
byte[] data = StreamTool.read(inputStream);
String result = new String(data);
return result;
}
return "failed";
}
下面的代碼是上面過程中從流中讀取數(shù)據(jù)的內(nèi)容。
public static class StreamTool {
//從流中讀取數(shù)據(jù)
public static byte[] read(InputStream inStream) throws Exception{
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while((len = inStream.read(buffer)) != -1)
{
outStream.write(buffer,0,len);
}
inStream.close();
return outStream.toByteArray();
}
}
2. 多條多元數(shù)據(jù)傳輸(Get方法)
對(duì)于多元的數(shù)據(jù)類型,我們可以采用json數(shù)組的方式進(jìn)行傳輸,首先定義一個(gè)包含我們需要的數(shù)據(jù)類型的類,這里我設(shè)置它包含三種不同的屬性,a1,a2,a3。
public class MultipleResult {
//類中包含多種不同類型的屬性
String a1;
int a2;
double a3;
public MultipleResult(String a1, int a2, double a3) {
this.a1 = a1;
this.a2 = a2;
this.a3 = a3;
}
}
在獲取時(shí),我們沿用單條數(shù)據(jù)傳輸?shù)乃悸?,只不過我們需要將獲取到的json數(shù)組轉(zhuǎn)換為Arraylist進(jìn)行存儲(chǔ),這里我設(shè)置了一個(gè)參數(shù)n,因?yàn)橥ǔG闆r下,我們都是在Android獲取參數(shù)作為關(guān)鍵字到云端數(shù)據(jù)庫(kù)中進(jìn)行查詢,然后返回查詢的結(jié)果,比如我們Android端獲取學(xué)生的學(xué)號(hào),在云端數(shù)據(jù)庫(kù)中查詢并且返回學(xué)生的信息。
//用于獲取多種復(fù)雜類型的數(shù)據(jù)
public static ArrayList<MultipleResult> multipleData(String n) throws Exception {
ArrayList<MultipleResult> list=new ArrayList<>();
String path="http://101.201.109.91/Connect_Android/get_multiple_data.php?n="+n;
HttpURLConnection conn = (HttpURLConnection) new URL(path).openConnection();
InputStream json = conn.getInputStream();
byte[] data = StreamTool.read(json);
String json_str = new String(data);
JSONArray jsonArray = new JSONArray(json_str);
for(int i = 0; i < jsonArray.length() ; i++){
JSONObject jsonObject = jsonArray.getJSONObject(i);
String a1=jsonObject.getString("a1");
int a2=jsonObject.getInt("a2");
double a3=jsonObject.getDouble("a3");
list.add(new MultipleResult(a1,a2,a3));
}
return list;
}
3. 文件傳輸(Post方法)
這里我直接沿用了另一位博主的文章,鏈接暫時(shí)找不到了,方式是設(shè)置Post的相關(guān)參數(shù),從本地的存儲(chǔ)地址傳到云端的存儲(chǔ)地址。我們需要在函數(shù)中寫入的參數(shù)有本地的存儲(chǔ)路徑,服務(wù)器端的存儲(chǔ)路徑,和文件名稱(這里的文件名稱可以是隨機(jī)定義的,是在服務(wù)器端最終顯示的文件名稱,可以與本地存儲(chǔ)路徑名稱不同)
public static void uploadFile(String path, String url_path, String name) {
String end = "\r\n";
String twoHyphens = "--";
String boundary = "*****";
try
{
URL url = new URL(url_path);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
/* Output to the connection. Default is false,
set to true because post method must write something to the connection */
con.setDoOutput(true);
/* Read from the connection. Default is true.*/
con.setDoInput(true);
/* Post cannot use caches */
con.setUseCaches(false);
/* Set the post method. Default is GET*/
con.setRequestMethod("POST");
/* 設(shè)置請(qǐng)求屬性 */
con.setRequestProperty("Connection", "Keep-Alive");
con.setRequestProperty("Charset", "UTF-8");
con.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
/*設(shè)置StrictMode 否則HTTPURLConnection連接失敗,因?yàn)檫@是在主進(jìn)程中進(jìn)行網(wǎng)絡(luò)連接*/
// StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectDiskReads().detectDiskWrites().detectNetwork().penaltyLog().build());
/* 設(shè)置DataOutputStream,getOutputStream中默認(rèn)調(diào)用connect()*/
DataOutputStream ds = new DataOutputStream(con.getOutputStream()); //output to the connection
ds.writeBytes(twoHyphens + boundary + end);
ds.writeBytes("Content-Disposition: form-data; " +
"name=\"file\";filename=\"" +
name+"\"" + end);
ds.writeBytes(end);
/* 取得文件的FileInputStream */
FileInputStream fStream = new FileInputStream(path);
/* 設(shè)置每次寫入8192bytes */
int bufferSize = 8192;
byte[] buffer = new byte[bufferSize]; //8k
int length = -1;
/* 從文件讀取數(shù)據(jù)至緩沖區(qū) */
while ((length = fStream.read(buffer)) != -1)
{
/* 將資料寫入DataOutputStream中 */
ds.write(buffer, 0, length);
}
ds.writeBytes(end);
ds.writeBytes(twoHyphens + boundary + twoHyphens + end);
/* 關(guān)閉流,寫入的東西自動(dòng)生成Http正文*/
fStream.close();
/* 關(guān)閉DataOutputStream */
ds.close();
/* 從返回的輸入流讀取響應(yīng)信息 */
InputStream is = con.getInputStream(); //input from the connection 正式建立HTTP連接
int ch;
StringBuffer b = new StringBuffer();
while ((ch = is.read()) != -1)
{
b.append((char) ch);
}
/* 顯示網(wǎng)頁響應(yīng)內(nèi)容 */
System.out.println(b.toString().trim());
//Toast.makeText(MainActivity.this, b.toString().trim(), Toast.LENGTH_SHORT).show();//Post成功
} catch (Exception e)
{
/* 顯示異常信息 */
System.out.println("fail"+e);
//Toast.makeText(MainActivity.this, "Fail:" + e, Toast.LENGTH_SHORT).show();//Post失敗
}
}
在Activity中的進(jìn)行調(diào)用使用
在xml文件中,我們?cè)O(shè)置了三個(gè)按鈕,和一個(gè)文本,分別進(jìn)行單條數(shù)據(jù)傳輸,多元數(shù)據(jù)傳輸,以及文件傳輸?shù)娘@示。
在activity中,我們將整個(gè)的方法整合為一個(gè)WebTool工具類,利用這個(gè)工具類調(diào)用上述的方法,同時(shí)需要注意的是,網(wǎng)絡(luò)連接不能再主線程中進(jìn)行,因此需要開辟一個(gè)新的線程進(jìn)行調(diào)用,同時(shí),對(duì)于前端控件的調(diào)用不能在分支線程中進(jìn)行,因此最后的結(jié)果顯示部分,我們用到了handler實(shí)現(xiàn)分支線程與主線程之間的通信,最終實(shí)現(xiàn)結(jié)果在TextView中顯示。
1. 單條數(shù)據(jù)傳輸調(diào)用
//在新線程中獲取數(shù)據(jù),通過handler判斷是否獲取到數(shù)據(jù)
//n為向PHP傳輸?shù)臄?shù)據(jù)
String n="本地測(cè)試數(shù)據(jù)";
result=WebTool.singleData("https://www.recycle11.top/Connect_Android/get_single_data.php?n="+n);
2. 多條多元數(shù)據(jù)調(diào)用
//n為測(cè)試數(shù)據(jù)
result_list=WebTool.multipleData("本地測(cè)試數(shù)據(jù)");
3. 文件傳輸
WebTool.uploadFile(test_file_path(),"https://www.recycle11.top/Connect_Android/upload.php","test.txt");
本地文件處理
本地文件處理借鑒了另一篇博文,由于沒有測(cè)試過Android 12版本,因此文件權(quán)限方面一定要處理好,否則無法獲取,寫入文件。
博文鏈接:本地文件的創(chuàng)建
在本地我們將文件夾創(chuàng)建,文件創(chuàng)建放入一個(gè)工具類FileUtil中,進(jìn)行處理,我們將寫入一個(gè)文件存入手機(jī)內(nèi)存中,并獲得它的路徑。
String test_file_path(){
File fileDir=new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/Connect_web_test");
String filename="test.txt";
//創(chuàng)建文件夾及文件
FileUtil.createFileDir(fileDir);
FileUtil.createFile(fileDir.getAbsolutePath(),filename);
//寫入文件信息
FileOutputStream fos = null;
try {
fos = new FileOutputStream(fileDir.getAbsolutePath()+"/"+filename);
String content="本地測(cè)試數(shù)據(jù)";
fos.write(content.getBytes());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try{
//保證即使出現(xiàn)異常,fos也可以正常關(guān)閉
fos.close();
} catch (IOException e){
e.printStackTrace();
}
}
return fileDir.getAbsolutePath()+"/"+filename;
}
二 PHP服務(wù)器端
在服務(wù)器端我們創(chuàng)建了如下的一些文件,設(shè)置了三個(gè)php文件接收并回傳信息,Android_File文件夾存儲(chǔ)Android端傳入的文件。
單條數(shù)據(jù)傳輸
<?php
if(is_array($_GET)&&count($_GET)>0){
if(isset($_GET['n'])){
$n=$_GET['n'];
}
}
echo "網(wǎng)絡(luò)數(shù)據(jù)內(nèi)容"
?>
多條多元數(shù)據(jù)傳輸
<?php
if(is_array($_GET)&&count($_GET)>0){
if(isset($_GET['n'])){
$n=$_GET['n'];
}
}
//根據(jù)傳過來的數(shù)據(jù)$n可作為關(guān)鍵字,查詢數(shù)據(jù)庫(kù)的信息,這里就不演示數(shù)據(jù)庫(kù)交互過程了
$content=array();
$content[0]=array("a1"=>"網(wǎng)絡(luò)測(cè)試數(shù)據(jù)1","a2"=>1,"a3"=>1.5);
$content[1]=array("a1"=>"網(wǎng)絡(luò)測(cè)試數(shù)據(jù)2","a2"=>2,"a3"=>2.5);
echo json_encode($content);
?>
文件傳輸
<?php
$target_path = "./Android_File/";//接收文件目錄
$target_path = $target_path . basename( $_FILES['file']['name']);
if(move_uploaded_file($_FILES['file']['tmp_name'], $target_path)) {
echo "The file ". basename( $_FILES['file']['name']). " has been uploaded";
}
else{
echo "There was an error uploading the file, please try again!" . $_FILES['file']['error'];
}
?>
最后我們?cè)谑謾C(jī)上進(jìn)行測(cè)試,出現(xiàn)如下效果就說明數(shù)據(jù)傳輸成功了。
單條數(shù)據(jù)傳輸
多條多元數(shù)據(jù)傳輸
文件傳輸
文章來源:http://www.zghlxwxcb.cn/news/detail-805656.html
PS:博主在測(cè)試完成后,將服務(wù)器端的代碼刪除了,因此利用本demo是無法訪問博主服務(wù)器的,也無法直接運(yùn)行,需要大家連接自己的服務(wù)器哦。文章來源地址http://www.zghlxwxcb.cn/news/detail-805656.html
到了這里,關(guān)于Android實(shí)現(xiàn)與PHP后端的交互(數(shù)據(jù)傳輸,文件傳輸)(超詳細(xì)/附源碼)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!