为方便大家浏览,源码先行奉上
github源码链接 https://github.com/Recycle1/Android-connect-PHP
csdn源码链接 https://download.csdn.net/download/weixin_52263647/87751491
在Android开发中,经常涉及与服务器端交互的过程,在现在的APP制作中,经常利用互联网通信,从云端获取图片,数据等信息,本篇文章将详细介绍Android与PHP后端进行交互的过程,即利用http进行通信的过程。
那熟悉PHP开发的我们都会知道PHP页面的传参方式有Get和Post,利用此原理我们即可实现Android端与PHP端的交互,Android端进行带参访问即进行Get方法传参,对于大规模的数据如文件的传输,利用Post方法,在Android端设置好相应的参数,进行大规模数据的传输。在之后的讲解中,我们将分情况进行演示。
在这篇文章中,我们需要准备的东西有:
- Android手机,这里我调试使用的是真机,测试所用的安卓版本为Android 10,当前普遍使用的Android 12版本可能会出现不适配的情况,比如文件读取和权限方面,这个只需稍加调试即可解决。
- 云服务器,这里我租用了阿里云的云服务器,并部署了SSL证书,(当然,如果只是android信息交互也可以不使用SSL证书)
那么接下来,我将分情况介绍如何进行Android与PHP的交互。
一 Android端
权限设置
对于互联网连接方面和文件读取方面,需要给予一定的权限,在manifest中设置
<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" />
文件读取与写入(尤其要看一下哦!!!)
本地文件读取与写入,同时需要在activity中动态给予权限。
//初始化权限
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);
}
}
同时,由于在本篇文章中要在手机内存中写入测试的文件,因此需要在Mainfest文件中的Application标签下设置如下权限,负责无法正常读取路径和写入文件。
android:requestLegacyExternalStorage="true"
http网络连接设置(也尤其要看一下哦!!!)
在本篇文章中,由于我的云服务器部署了SSL证书和域名,因此可以利用https进行访问,但是如果没有SSL证书和域名,我们要利用IP地址进行访问,那需要在Mainfest文件中的Application标签下设置如下权限,负责无法正常连接到服务器。
android:usesCleartextTraffic="true"
1. 单条数据传输(Get方法)
单条数据的传输,我们在Android端传入字符串,服务器端也会返回字符串,利用http建立连接。
//主要用于传输单条数据,如字符串等,同时,PHP端也返回单条数据
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";
}
下面的代码是上面过程中从流中读取数据的内容。
public static class StreamTool {
//从流中读取数据
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. 多条多元数据传输(Get方法)
对于多元的数据类型,我们可以采用json数组的方式进行传输,首先定义一个包含我们需要的数据类型的类,这里我设置它包含三种不同的属性,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;
}
}
在获取时,我们沿用单条数据传输的思路,只不过我们需要将获取到的json数组转换为Arraylist进行存储,这里我设置了一个参数n,因为通常情况下,我们都是在Android获取参数作为关键字到云端数据库中进行查询,然后返回查询的结果,比如我们Android端获取学生的学号,在云端数据库中查询并且返回学生的信息。
//用于获取多种复杂类型的数据
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方法)
这里我直接沿用了另一位博主的文章,链接暂时找不到了,方式是设置Post的相关参数,从本地的存储地址传到云端的存储地址。我们需要在函数中写入的参数有本地的存储路径,服务器端的存储路径,和文件名称(这里的文件名称可以是随机定义的,是在服务器端最终显示的文件名称,可以与本地存储路径名称不同)
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");
/* 设置请求属性 */
con.setRequestProperty("Connection", "Keep-Alive");
con.setRequestProperty("Charset", "UTF-8");
con.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
/*设置StrictMode 否则HTTPURLConnection连接失败,因为这是在主进程中进行网络连接*/
// StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectDiskReads().detectDiskWrites().detectNetwork().penaltyLog().build());
/* 设置DataOutputStream,getOutputStream中默认调用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);
/* 设置每次写入8192bytes */
int bufferSize = 8192;
byte[] buffer = new byte[bufferSize]; //8k
int length = -1;
/* 从文件读取数据至缓冲区 */
while ((length = fStream.read(buffer)) != -1)
{
/* 将资料写入DataOutputStream中 */
ds.write(buffer, 0, length);
}
ds.writeBytes(end);
ds.writeBytes(twoHyphens + boundary + twoHyphens + end);
/* 关闭流,写入的东西自动生成Http正文*/
fStream.close();
/* 关闭DataOutputStream */
ds.close();
/* 从返回的输入流读取响应信息 */
InputStream is = con.getInputStream(); //input from the connection 正式建立HTTP连接
int ch;
StringBuffer b = new StringBuffer();
while ((ch = is.read()) != -1)
{
b.append((char) ch);
}
/* 显示网页响应内容 */
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中的进行调用使用
在xml文件中,我们设置了三个按钮,和一个文本,分别进行单条数据传输,多元数据传输,以及文件传输的显示。
在activity中,我们将整个的方法整合为一个WebTool工具类,利用这个工具类调用上述的方法,同时需要注意的是,网络连接不能再主线程中进行,因此需要开辟一个新的线程进行调用,同时,对于前端控件的调用不能在分支线程中进行,因此最后的结果显示部分,我们用到了handler实现分支线程与主线程之间的通信,最终实现结果在TextView中显示。
1. 单条数据传输调用
//在新线程中获取数据,通过handler判断是否获取到数据
//n为向PHP传输的数据
String n="本地测试数据";
result=WebTool.singleData("https://www.recycle11.top/Connect_Android/get_single_data.php?n="+n);
2. 多条多元数据调用
//n为测试数据
result_list=WebTool.multipleData("本地测试数据");
3. 文件传输
WebTool.uploadFile(test_file_path(),"https://www.recycle11.top/Connect_Android/upload.php","test.txt");
本地文件处理
本地文件处理借鉴了另一篇博文,由于没有测试过Android 12版本,因此文件权限方面一定要处理好,否则无法获取,写入文件。
博文链接:本地文件的创建
在本地我们将文件夹创建,文件创建放入一个工具类FileUtil中,进行处理,我们将写入一个文件存入手机内存中,并获得它的路径。
String test_file_path(){
File fileDir=new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/Connect_web_test");
String filename="test.txt";
//创建文件夹及文件
FileUtil.createFileDir(fileDir);
FileUtil.createFile(fileDir.getAbsolutePath(),filename);
//写入文件信息
FileOutputStream fos = null;
try {
fos = new FileOutputStream(fileDir.getAbsolutePath()+"/"+filename);
String content="本地测试数据";
fos.write(content.getBytes());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try{
//保证即使出现异常,fos也可以正常关闭
fos.close();
} catch (IOException e){
e.printStackTrace();
}
}
return fileDir.getAbsolutePath()+"/"+filename;
}
二 PHP服务器端
在服务器端我们创建了如下的一些文件,设置了三个php文件接收并回传信息,Android_File文件夹存储Android端传入的文件。
单条数据传输
<?php
if(is_array($_GET)&&count($_GET)>0){
if(isset($_GET['n'])){
$n=$_GET['n'];
}
}
echo "网络数据内容"
?>
多条多元数据传输
<?php
if(is_array($_GET)&&count($_GET)>0){
if(isset($_GET['n'])){
$n=$_GET['n'];
}
}
//根据传过来的数据$n可作为关键字,查询数据库的信息,这里就不演示数据库交互过程了
$content=array();
$content[0]=array("a1"=>"网络测试数据1","a2"=>1,"a3"=>1.5);
$content[1]=array("a1"=>"网络测试数据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'];
}
?>
最后我们在手机上进行测试,出现如下效果就说明数据传输成功了。
单条数据传输
多条多元数据传输
文件传输
文章来源:https://www.toymoban.com/news/detail-805656.html
PS:博主在测试完成后,将服务器端的代码删除了,因此利用本demo是无法访问博主服务器的,也无法直接运行,需要大家连接自己的服务器哦。文章来源地址https://www.toymoban.com/news/detail-805656.html
到了这里,关于Android实现与PHP后端的交互(数据传输,文件传输)(超详细/附源码)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!