Android部分手机4G网第一次请求很慢(wifi正常)解决方案

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: Android部分手机4G网第一次请求很慢(wifi正常)解决方案

抓住人生中的一分一秒,胜过虚度中的一月一年!

背景

最近,客户突然反馈一个问题,手机4G网网络请求特别慢,卡了快30s左右,之后网络请求就正常了,但是项目杀掉,重新打开,又卡了30s左右,问题反馈过来一脸懵逼状态,从来没有遇到过这种情况,然而手边所有测试机都属于正常现象,于是开始研究什么问题造成的

分析

网上查了查,答案都指向了DNS解析设置的问题,解析有两种 ipv4 ipv6 ,android默认不支持ipv6解析,之后问了下后台配置,说IOS 的 appstore 审核,必须需要ipv6的配置才能正常进行,所以服务端增加了 ipv6 支持,同时也支持ipv4,但是ipv6的入口再美国,那这样看来,猜测是否是android手机默认通过ipv6去连接后端服务器,绕了一大圈才返回结果?于是,各个问题都分别科普下

1、android为何不支持ipv6解析

IPv4地址即将枯竭,这种警告已经发出了一次又一次,但是IPv6依然迟迟无法普及,原因之一就是有些巨头不提供支持。

Windows、Linux、Mac OS X、iOS等系统都已经支持了IPv6,但是Google Android却迟迟不肯加入。要知道,Android设备的规模已达几十亿,占据了智能手机市场的几乎八成,它不支持IPv6无疑是极大的桎梏。

由于不支持新的IP地址动态分配协议DHCPv6,Android设备在无线网络中经常处于不利地位,这也让很多网络管理人员很郁闷。为此,不少公司甚至禁止在企业网络中使用Android设备,这也给他们的IPv6部署产生了很大的阻碍。

不少专业人士对Google的迟缓感到十分不满,尤其是在Google Code的一个帖子中,很多人甚至愤怒得破口大骂。

不过在Google开发者、IPv6权威专家Lorenzo Colliti看来,Android不支持IPv6也是有苦衷的,比如会影响那些依赖IPv4的应用,无法强制开发者采用IPv6网络地址,地址转换后性能会有损失等等。

2、为何要支持ipv6

苹果公司的App审核人员进行审核时,由于国内大部分开发者的服务器不支持IPv6-Only访问,因此只能通过苹果公司自己的NAT64+DNS64服务器进行测试,如果苹果的服务器不能有效的给AppServer返回一个IPv6地址,就会导致无法访问等问题。其结果便是审核失败,App被拒。

排查

目前发现部分手机出现网络请求慢问题(小米手机),但是一般手机都属于正常

于是使用以下代码 DNS 解析的 IP 地址

try {
   InetAddress[] mInetAddresses= InetAddress.getAllByName("xxxx.cn");
   for(InetAddress address: mInetAddresses){
     System.out.println(address.getHostAddress());
   }
} catch (UnknownHostException e) {
   e.printStackTrace();
}

发现

1、连接到公司wifi,只解析到 ipv4 地址

2、连接到4G网,解析到了ipv4、ipv6俩个地址

但是ipv6默认为集合中的第一个,是否我们可以尝试修改集合第一个为ipv4呢?

自定义okhttp中dns解析

查看了下okhttp开放了自定义dns方法,于是追踪到源码可以看到

package okhttp3;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.List;
/**
 * A domain name service that resolves IP addresses for host names. Most applications will use the
 * {@linkplain #SYSTEM system DNS service}, which is the default. Some applications may provide
 * their own implementation to use a different DNS server, to prefer IPv6 addresses, to prefer IPv4
 * addresses, or to force a specific known IP address.
 *
 * <p>Implementations of this interface must be safe for concurrent use.
 */
public interface Dns {
  /**
   * A DNS that uses {@link InetAddress#getAllByName} to ask the underlying operating system to
   * lookup IP addresses. Most custom {@link Dns} implementations should delegate to this instance.
   */
  Dns SYSTEM = new Dns() {
    @Override public List<InetAddress> lookup(String hostname) throws UnknownHostException {
      if (hostname == null) throw new UnknownHostException("hostname == null");
      try {
        return Arrays.asList(InetAddress.getAllByName(hostname));
      } catch (NullPointerException e) {
        UnknownHostException unknownHostException =
            new UnknownHostException("Broken system behaviour for dns lookup of " + hostname);
        unknownHostException.initCause(e);
        throw unknownHostException;
      }
    }
  };
  /**
   * Returns the IP addresses of {@code hostname}, in the order they will be attempted by OkHttp. If
   * a connection to an address fails, OkHttp will retry the connection with the next address until
   * either a connection is made, the set of IP addresses is exhausted, or a limit is exceeded.
   */
  List<InetAddress> lookup(String hostname) throws UnknownHostException;
}

于是我们去调换集合中ipv4 ipv6位置,将ipv4当到集合首位

import okhttp3.Dns;
/**
 * File descripition:
 *
 * @author lp
 * @date 2019/4/16
 */
public class ApiDns implements Dns {
    @Override
    public List<InetAddress> lookup(String hostname) throws UnknownHostException {
        if (hostname == null) {
            throw new UnknownHostException("hostname == null");
        } else {
            try {
                List<InetAddress> mInetAddressesList = new ArrayList<>();
                InetAddress[] mInetAddresses = InetAddress.getAllByName(hostname);
                for (InetAddress address : mInetAddresses) {
                    if (address instanceof Inet4Address) {
                        mInetAddressesList.add(0, address);
                    } else {
                        mInetAddressesList.add(address);
                    }
                }
                return mInetAddressesList;
            } catch (NullPointerException var4) {
                UnknownHostException unknownHostException = new UnknownHostException("Broken system behaviour");
                unknownHostException.initCause(var4);
                throw unknownHostException;
            }
        }
    }
}

将自定义方法插入到okhttp中

OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
        ClearableCookieJar cookieJar =
                new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(AppUMS.mContent));
        httpClientBuilder
                .cookieJar(cookieJar)
                .addInterceptor(interceptor)
                .addInterceptor(new HeadUrlInterceptor())
                //设置请求超时时长
                .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                .writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                .readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                .retryOnConnectionFailure(true)//错误重联
                .dns(new ApiDns());

安装到以前访问慢的小米手机上,访问回归正常

最后补充

网上查到的解决办法说的是苹果审核阶段暂时开启ipv6,审核通过上线关闭ipv6,这样完全是可以的,但是治标不治本,如上操作就没必要一次一次修改了,本人测试红米6,大家有好的方法可以提出来共享下

相关文章
|
5月前
|
网络协议 Android开发 数据安全/隐私保护
Android手机上使用Socks5全局代理-教程+软件
Android手机上使用Socks5全局代理-教程+软件
4116 2
|
11天前
|
传感器 数据采集 移动开发
基于STM32的智能手环wifi连接手机APP(下)
基于STM32的智能手环wifi连接手机APP(下)
45 0
|
3月前
|
存储 安全 Android开发
"解锁Android权限迷宫:一场惊心动魄的动态权限请求之旅,让你的应用从平凡跃升至用户心尖的宠儿!"
【8月更文挑战第13天】随着Android系统的更新,权限管理变得至关重要。尤其从Android 6.0起,引入了动态权限请求,增强了用户隐私保护并要求开发者实现更精细的权限控制。本文采用问答形式,深入探讨动态权限请求机制与最佳实践,并提供示例代码。首先解释了动态权限的概念及其重要性;接着详述实现步骤:定义、检查、请求权限及处理结果;最后总结了六大最佳实践,包括适时请求、解释原因、提供替代方案、妥善处理拒绝情况、适应权限变更及兼容旧版系统,帮助开发者打造安全易用的应用。
62 0
|
22天前
|
Ubuntu Linux Android开发
termux+anlinux+Rvnc viewer来使安卓手机(平板)变成linux服务器
本文介绍了如何在Android设备上安装Termux和AnLinux,并通过这些工具运行Ubuntu系统和桌面环境。
86 2
termux+anlinux+Rvnc viewer来使安卓手机(平板)变成linux服务器
|
18天前
|
Web App开发 Android开发
利用firefox调试安卓手机端web
该教程详细介绍如何通过Firefox浏览器实现手机与电脑的远程调试。手机端需安装最新版Firefox,并按指定步骤设置完成;电脑端则需安装15版及以上Firefox。设置完成后,通过工具栏中的“远程调试”选项,输入手机IP地址即可连接。连接确认后,即可使用电脑端Firefox调试器调试手机上的Web信息。注意,调试前手机需提前打开目标网页。
34 2
|
3天前
|
Android开发 iOS开发 UED
安卓与iOS的较量:谁才是智能手机市场的王者?
本文将深入探讨安卓和iOS两大智能手机操作系统之间的竞争关系,分析它们各自的优势和劣势。通过对比两者在市场份额、用户体验、应用生态等方面的表现,我们将揭示出谁才是真正的市场领导者。无论你是安卓粉丝还是iOS忠实用户,这篇文章都将为你提供一些有趣的观点和见解。
|
11天前
|
传感器 存储 编解码
基于STM32的智能手环wifi连接手机APP(上)
基于STM32的智能手环wifi连接手机APP(上)
23 0
|
2月前
|
存储 API Android开发
"解锁Android权限迷宫:一场惊心动魄的动态权限请求之旅,让你的应用从平凡跃升至用户心尖的宠儿!"
随着Android系统的更新,权限管理成为应用开发的关键。尤其在Android 6.0(API 级别 23)后,动态权限请求机制的引入提升了用户隐私保护,要求开发者进行更精细的权限管理。
59 2
|
3月前
|
Android开发
【Azure 环境】记录使用Notification Hub,安卓手机收不到Push通知时的错误,Error_Code 30602 or 30608
【Azure 环境】记录使用Notification Hub,安卓手机收不到Push通知时的错误,Error_Code 30602 or 30608
|
4月前
|
存储 移动开发 Android开发
使用kotlin Jetpack Compose框架开发安卓app, webview中h5如何访问手机存储上传文件
在Kotlin和Jetpack Compose中,集成WebView以支持HTML5页面访问手机存储及上传音频文件涉及关键步骤:1) 添加`READ_EXTERNAL_STORAGE`和`WRITE_EXTERNAL_STORAGE`权限,考虑Android 11的分区存储;2) 配置WebView允许JavaScript和文件访问,启用`javaScriptEnabled`、`allowFileAccess`等设置;3) HTML5页面使用`<input type="file">`让用户选择文件,利用File API;