simplexmlconverter在android 8.0+需配置network_security_config允许http明文流量;不支持list直接解析,须用@elementlist(inline=true)的根容器类;需排除xpp3冲突、确保无参构造函数、注意kotlin字段可见性及xml命名空间严格匹配。

SimpleXmlConverter不支持Android 8.0+默认禁用HTTP明文流量
直接跑不起来,多半是这个原因。Android 8.0(API 26)起,默认禁止应用使用明文 HTTP 请求,而很多老 XML 接口还在用 http:// 地址。retrofit 本身不拦,但底层 okhttp 会直接抛 java.net.UnknownServiceException: CLEARTEXT communication to xxx not permitted by network security policy。
实操建议:
- 检查接口地址是否为
http://—— 如果是,要么切到https://,要么在res/xml/network_security_config.xml中显式允许该域名的明文通信 - 别只改
AndroidManifest.xml的android:usesCleartextTraffic="true",它在 targetSdkVersion ≥ 28 时对部分域名(如 localhost)也不生效,必须配network_security_config - SimpleXmlConverter 本身不处理网络层,它只管把响应体字节流反序列化成 Java 对象,所以网络不通、404、500 都不是它的问题
SimpleXmlConverterFactory.create() 默认不支持 List 直接解析
写个接口返回一串 <items><item>...</item><item>...</item></items>,然后定义 Call<list>></list>,大概率会崩:Gson 可以这么干,SimpleXML 不行——它需要一个**根容器类**,不能直接映射到裸 List。
常见错误现象:org.simpleframework.xml.core.PersistenceException: constructor not matched for class java.util.ArrayList
实操建议:
- 定义一个包装类,比如
ItemsResponse,里面用@ElementList(inline = true)声明List<item> items</item> -
inline = true很关键:它告诉 SimpleXML 跳过外层<items></items>标签,直接从子节点开始解析;不加的话,XML 必须是<itemsresponse><items><item>...</item></items></itemsresponse> - 别在
Item类里漏掉无参构造函数——SimpleXML 反射实例化时强依赖它
SimpleXML 在 Android 上需手动排除 XPP3 冲突
项目里如果用了其他库(比如旧版 OkHttp、某些支付 SDK),很可能自带了 xpp3 或 xstream,而 SimpleXML 依赖的 simple-xml 默认打包了它自己的 xpp3 实现。运行时可能报 NoClassDefFoundError 或 VerifyError,尤其在 dalvik(低版本 Android)上更明显。
实操建议:
- 在
app/build.gradle的dependencies里,对simple-xml做exclude:implementation('org.simpleframework:simple-xml:2.7.1') { exclude group: 'xpp3', module: 'xpp3' } - 同时显式引入轻量兼容版:
implementation 'xpp3:xpp3:1.1.4c'(别用 1.1.3.x,有已知 Android 字符集 bug) - 如果用了 Kotlin,注意
@Root、@Element这些注解要加在val字段上,且字段不能是private——SimpleXML 不读 Kotlin 编译后的 getter/setter
SimpleXML 解析失败时很难定位具体哪一行出错
不像 json 有明确的 offset 和 Token 错误,SimpleXML 报错经常是 Unexpected token 或 Expected start tag,但没告诉你 XML 第几行、哪个标签。尤其当服务端返回 HTML 错误页(比如 404 时返回了 nginx 默认页)却当成 XML 解析,就更难排查。
实操建议:
- 先用 OkHttp 的
LoggingInterceptor打印原始响应体,确认返回的是真 XML,且编码是 UTF-8(SimpleXML 默认按 UTF-8 解码,服务端若用 GBK 会乱码) - 在 Converter 里临时加一层包装:继承
SimpleXmlResponseBodyConverter,在convert()里 catch 异常后打印response.body().String()前 512 字符(注意只能读一次) - XML 命名空间(
xmlns)必须严格匹配:服务端写了xmlns="http://xxx",你的@Root(Namespace = "http://xxx")就不能少,也不能多空格
真正麻烦的从来不是怎么写注解,而是服务端 XML 格式松散、文档缺失、偶尔夹带 bom 或非法字符——这些没法靠加依赖解决,得靠日志和耐心对齐。