在Android app中,网络操作是不可或缺的一个模块,手机中数据的上传下载都需要通过app中的网络操作模块进行。
在Android进行http请求操作有多种方式,在这里我简单说一下最基础的用HttpURLConnection进行网络操作的方法
一、向设备申请网络权限
首先需要向设备申请网络权限。
如果是Android9.0以前版本的设备,只需要在AndroidManifest.xml文件中添加一个与<application>同级的标签即可
<uses-permission android:name="android.permission.INTERNET"/>
从Android9.0开始增加了对http请求的限制,在添加上面的标签之后,还需要我们另外创建安全配置文件:
1、在res文件夹下创建xml/network-security-config.xml文件
2、在netnetwork-security-config.xml中添加cleartextTrafficPermitted属性(是否允许网络通信使用明文网络流量)
xml文件内容如下:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true"/>
</network-security-config>
3、指定安全配置文件
在AndroidManifest中的Application标签里申明配置文件
android:networkSecurityConfig="@xml/network_security_config"
二、在Activity中进行http请求
首先在mainlayout中创建一个id为myclick的Button。
然后是在Activity中的操作:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mainlayout);
}
public void get() {
try {
//实例化URL对象
URL url = new URL("http://www.imooc.com/api/teacher?type=3&cid=1");
//获取HTTPURLConnection实例
HttpURLConnection httpconn = (HttpURLConnection)url.openConnection();
//设置请求相关属性
//设置方式
httpconn.setRequestMethod("GET");
//设置请求时长
httpconn.setConnectTimeout(5000);
//获取响应码 200:成功 404:未请求到指定资源 500:服务器异常
if (httpconn.getResponseCode() == HttpURLConnection.HTTP_OK) {
InputStream in = httpconn.getInputStream();
byte[] b = new byte[1024];
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int length = 0;
while ((length = in.read(b)) > -1) {
//不能不做判断直接in.read(b),因为若数据读完了,输入流还会继续读,只是内容为空,这时循环会继续。
// 而当in.read()取值为-1时则代表已经没有内容了
baos.write(b, 0,length);
}
String str = new String(baos.toString());
Log.i("MainActivity", str + "----------------");
};
}
catch (MalformedURLException e1) {
e1.printStackTrace();
} catch (IOException e2) {
e2.printStackTrace();
}
}
public void myclick(View view) {
switch(view.getId()) {
case R.id.get:
new Thread() {
@Override
public void run() {
super.run();
get();
}
}.start();
break;
}
}
}
在做好前面两步后安装apk到设备中,点击按钮即可在AS中的Logcat中查看获取到的信息。
三、可能遇到的报错
在这里简单列举在网络操作中可能遇到的一些报错情况:
1、NetworkOnMainThreadException
如果遇到NetworkOnMainThreadException报错的,则说明网络请求操作在主线程中进行了,我们需要开一个子线程进行网络请求
如前面我给出的例子,则是将get()操作放在子线程中进行:
public void myclick(View view) {
switch(view.getId()) {
case R.id.get:
new Thread() {
@Override
public void run() {
super.run();
get();
}
}.start();
break;
}
}
2、SecurityException
遇到java.lang.SecurityException: Permission denied (missing INTERNET permission?)
这种报错的一般是没有在AndroidManifest中申请网络权限
解决办法:在AndroidManifest文件中<application>标签外添加网络权限申请标签:
<uses-permission android:name=”android.permission.INTERNET”/>
3、NetworkSecurityConfig
遇到这种报错是因为在Android9.0后面的版本增加了对http请求的限制,需要我们另外创建安全配置文件:
1)在res文件夹下创建xml/network_security_config.xml文件
2)在network_security_config.xml文件中添加cleartextTrafficPermitted属性
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true"/>
</network-security-config>
3)指定安全配置文件
在AndroidManifest.xml中的Application添加申明(引用刚才创建的安全配置文件的地址)
android:networkSecurityConfig="@xml/network_security_config"
4、SocketException
这种情况一般为多次调试程序后出现,如新添加的配置文件没有安装进设备,则可能出现这个exception
解决方法:卸载程序后重新安装运行即可
拓展:
Android P的新特性:网络安全配置
Android 9中全面禁止了非安全的http连接,如果要使用非加密连接,则需要配置network security config文件。
1、首先,在res/xml文件夹下建立network security config文件,名字任意,可以命名为network-security-config.xml
2、在netnetwork-security-config.xml中添加cleartextTrafficPermitted属性(是否允许网络通信使用明文网络流量)
xml文件内容如下:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<!-- 允许所有网址使用非安全连接-->
<base-config cleartextTrafficPermitted="true"/>
</network-security-config>
应用可以使用 base-config(应用范围的自定义)或 domain-config(针对每个网域的自定义)自定义自己的连接。
例如,应用可能需要确保所有与 secure.example.com 的连接始终通过 HTTPS 完成,以防止来自恶意网络的敏感流量。
这时可以这样配置:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<!-- 不允许secure.example.com网域使用非安全连接 -->
<domain-config cleartextTrafficPermitted="false">
<domain includeSubdomains="true">secure.example.com</domain>
</domain-config>
</network-security-config>
3、指定安全配置文件
在AndroidManifest中的Application标签里声明配置文件
<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
<application android:networkSecurityConfig="@xml/network-security-config"
... >
...
</application>
</manifest>
除此之外,我们还可以配置信任的CA证书。
配置自定义 CA
假设您要连接到使用自签名 SSL 证书的主机,或者连接到其 SSL 证书由您信任的非公共 CA(如公司的内部 CA)颁发的主机。
res/xml/network-security-config.xml:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config>
<domain includeSubdomains="true">example.com</domain>
<trust-anchors>
<!-- 自己的非公共CA -->
<certificates src="@raw/my_ca"/>
</trust-anchors>
</domain-config>
</network-security-config>
以 PEM 或 DER 格式将自签名或非公共 CA 证书添加到 res/raw/my_ca
。
限制可信 CA 集
如果应用并不一定想要信任系统信任的所有 CA,则可以自行指定,即缩减要信任的 CA 集。这样可防止应用信任由任何其他 CA 颁发的欺诈性证书。
限制可信 CA 集的配置与针对特定网域信任自定义CA 相似,不同的是,前者要在资源中提供多个 CA。
res/xml/network_security_config.xml:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config>
<domain includeSubdomains="true">secure.example.com</domain>
<domain includeSubdomains="true">cdn.example.com</domain>
<trust-anchors>
<certificates src="@raw/trusted_roots"/>
</trust-anchors>
</domain-config>
</network-security-config>
以 PEM 或 DER 格式将可信 CA 添加到 res/raw/trusted_roots
。请注意,如果使用 PEM 格式,文件必须仅包含 PEM 数据,且没有额外的文本。您还可以提供多个 <certificates>
,而不是只提供一个。
信任其他 CA
应用可能需要信任系统不信任的其他 CA,出现此情况的原因可能是系统还未包含此 CA,或 CA 不符合添加到 Android 系统中的要求。应用可以通过为一个配置指定多个证书源来实现此目的。
res/xml/network_security_config.xml
:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config>
<trust-anchors>
<certificates src="@raw/extracas"/>
<certificates src="system" /> <!-- 系统内置的CA证书 -->
<certificates src="user" /> <!-- 用户自己安装的CA证书 -->
</trust-anchors>
</base-config>
</network-security-config>
拓展部分借鉴资料链接:
Android P新特性、 网络安全配置|Android Developers