使用warp解决vir,rn等谷歌验证码问题

什么是wrap? Cloudflare官网解释,wrap是为个体或组织提供一个更快,更安全,更有隐私体验的专线。为了不通的网络需求,wrap有多种模式。 wrap都有什么模式? 1.1.1.1 1.1.1.1是cf的公共DNS解析器,提供了更快更安全的网络浏览,它也通过DNS over HTTPS 或DNS over TLS提供加密服务,以提高安全和隐私 1.1.1.1 with wrap wrap使用 BoringTUN 加密从设备发出的数据并直接发送刀CloudFlare的边缘网络。保证了用户安全,阻止了第三方查看网络上传输的数据  warp via LOCAL PROXY 目前只支持桌面客户端,wrap配置为本代理,只有配置了代理的应用的数据才会走wrap warp+ 能够利用CloudFlare世界众多的数据中心提供更加私有和健硕的网络连接,提高整体端对端的性能  warp unlimited warp+的按月订阅服务,目前只能通过安卓和ios终端订阅 使用warp过vir,rn的谷歌验证 使用warp的一键脚本  https://github.com/P3TERX/warp.sh ipv4出栈由warp接管 bash <(curl -fsSL git.io/warp.sh) wg4 2. ipv4和ipv6双栈都由warp接管 bash <(curl -fsSL git.io/warp.sh) wgd 3. 用wrap给没有ipv6的vps添加ipv6,然后v2单独配置谷歌走ipv6 bash <(curl -fsSL git.io/warp.sh) wg6  v2客户端需要添加配置让特定地址走ipv6 outbounds里面添加:     {       "tag":"IP4_out",       "protocol": "freedom",       "settings": {}     },     {       "tag":"IP6_out",       "protocol": "freedom",       "settings": {         "domainStrategy": "UseIPv6"       }      } routing里面添加:       {         "type": "field",         "outboundTag": "IP6_out",         "domain": ["geosite:netflix","geosite:google"]        },       { … Read more

Android Handler 原理-Handler

Handler允许发送和处理与线程的MessageQueue相关联Message和Runnable对象。每一个Handler实例都与一个单独的线程和该线程的消息队列相关联。当创建Handler的时候,它被它创建的线程绑定。它把Message或Runnable对象传递到消息队列,出队的时候执行它们。Handler有两个主要用处:1.调度消息和Runnable在未来的某个时间点执行。2.入队一个操作并在不同的线程上执行。 调度消息通过post,postAtTime(Runnable,long),postDelayed,sendEmptyMessage,sendMessage,sendMessageAtTime,sendMessageDelayed方法完成。post版本允许入队Runnable对象,sendMessage版本允许入队Message对象,Message对象包含的数据会被Handler的handleMessage方法处理(需要自己实现Handler的子类)。 post或send的时候可以允许item在消息队列准备好的时候立即处理,或者定义一个时间延迟或确切的时间处理。 当一个应用的进程创建完,它的主线程专注运行一个消息队列,负责管理高级别的应用对象(Activity,BroadcastReceiver等)和他们创建的window,我们可以创建自己的子线程,并通过Handler和主线程通信。这样是通过在子线程里调用post或sendMessage方法完成。然后Runnable或Message将在Handler的消息队列里调度,在合适的时候处理。 构造函数 Handler总共有7个构造函数 #无参构造函数,内部调用6,callback传null,async传false 1. public Handler() {         this(null, false);     } #设置消息处理回调,内部调用6,async传false 2. public Handler(@Nullable Callback callback) {         this(callback, false);     }   #设置Looper,这样就不用调用Looper.prepare方法,内部调用7 3. public Handler(@NonNull Looper looper) {         this(looper, null, false);     }     #设置Looper和回调,内部调用7 4. public Handler(@NonNull Looper looper, @Nullable Callback callback) {         this(looper, callback, false);     }     #设置消息是否异步,内部调用6 5. public Handler(boolean async) {         this(null, async);     }     #设置回调和是否异步,内部检测looper是否为空,所以所有内部调用这个方法的构造函数都需要先调用Looper.prepare方法初始化Looper和MessageQueue 6. public Handler(@Nullable Callback callback, boolean async) {         if (FIND_POTENTIAL_LEAKS) {             final Class<? extends Handler> klass = getClass();             if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&                     (klass.getModifiers() & Modifier.STATIC) == 0) {                 Log.w(TAG, "The following Handler class should be static or leaks might occur: " +                     klass.getCanonicalName());             }         }         mLooper = Looper.myLooper();         if (mLooper == null) {             throw new RuntimeException(                 "Can't create handler inside thread " + Thread.currentThread()                         + " that has not called Looper.prepare()");         }         mQueue = mLooper.mQueue;         mCallback = callback;         mAsynchronous = async;     }  #设置Looper,回调,是否异步    7. public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {         mLooper = looper;         mQueue = looper.mQueue;         mCallback = callback;         mAsynchronous = async;     } Handler总共有7个构造函数,分别应用在不同场景下,可以设置消息是否异步,设置Looper,回调。 消息处理 … Read more

Android Handler 原理-Looper

Looper在Handler机制中主要在线程中进行消息循环。线程中默认没有关联的Looper。在线程调用Looper.prepare方法创建关联的looper,调用Looper.loop方法处理消息,直到loop停止。大部分与消息循环的交互是通过Handler类。官方文档给出了一个简单实例实现了一个Looper线程,使用prepare和loop常见一个Handler与Looper通信。 class LooperThread extends Thread {          public Handler mHandler;              public void run() {              Looper.prepare();                  mHandler = new Handler() {                  public void handleMessage(Message msg) {                      // process incoming messages here                  }              };                  Looper.loop();          }      } Looper.prepare 通过ThreadLocal存储当前线程的Looper实例 #线程本地变量存储Looper实例 static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); final MessageQueue mQueue;#关联的消息队列 final Thread mThread; #创建Looper的线程  public static void prepare() {         prepare(true);     }     private static void prepare(boolean quitAllowed) {         if (sThreadLocal.get() != null) {          #prepare只允许调用一次              throw new RuntimeException("Only one Looper may be created per thread");         }         sThreadLocal.set(new Looper(quitAllowed)); #新实例创建,存入本地线程变量副本     }       private Looper(boolean quitAllowed) {         mQueue = new MessageQueue(quitAllowed); #消息队列实例化         mThread = Thread.currentThread(); #创建的线程     } preprare参数quitAllowed代表跟Looper关联的MessageQueue是否允许退出,默认允许,Looper实例化的同时,也实例化了关联的MessageQueue,给线程变量mThread赋值,主线程的MessageQueue是不允许退出的,在ActivityThread的main方法中调用Looper.prepareMainLooper方法,内部prepare传参为false,表示不允许退出。 消息循环,Looper.loop public static @Nullable Looper myLooper() {         return sThreadLocal.get();     } public static void loop() {         final Looper me = myLooper();         if (me == null) {             #没有调用prepare方法,线程本地变量获取不到looper实例,直接抛出异常              throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");         }         final MessageQueue queue = me.mQueue;        ….         boolean slowDeliveryDetected = false;         for (;;) {            #从MessageQueue取消息,             Message msg = queue.next(); // might block             if (msg == null) {                 // 没有消息,消息队列正在退出 … Read more

Android Handler原理-MessageQueue

MessageQueue是一个低级别的类,持有一个由Looper传递的消息列表。Message不是直接添加到MessageQueue里的。而是由跟Looper关联的Handler对象添加的。 可以通过Looper.myQueue()方法提取跟当前线程关联的MessageQueue。 MessageQueue的构造函数:  MessageQueue(boolean quitAllowed) {         mQuitAllowed = quitAllowed;         mPtr = nativeInit();     } mQuitAllowed表示是否允许退出,mPtr是navite函数的返回值,nativeInit位于C++层/frameworks/base/core/jni/android_os_MessageQueue.cpp文件内: static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {     NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();     if (!nativeMessageQueue) {         jniThrowRuntimeException(env, "Unable to allocate native queue");         return 0;     }    nativeMessageQueue->incStrong(env);     return reinterpret_cast<jlong>(nativeMessageQueue); }     首先实例化NaviteMessageQue,然后强制转换成long类型返回,那么mPtr就是一个指向NativeMessageQueue的指针,MessageQueue初始化的时候由nativeInit赋值,销毁的时候在finalizelize方法里调用dispose方法置零。  private void dispose() {         if (mPtr != 0) {             nativeDestroy(mPtr);             mPtr = 0;         }     }     回过头看构造函数,形参quitAllowed表示是否允许退出消息队列,主线程这个参数会传递成false,表示不允许退出,在ActivityThread的main方法里调用Looper.prepareMainLooper(),最终调用Lopper的构造函数,在构造函数里初始化MessageQueue,quitAllowed传参false。  private Looper(boolean quitAllowed) {         mQueue = new MessageQueue(quitAllowed);         mThread = Thread.currentThread();     } 我们平时调用Looper.prepare(),方法的时候,构造的MessageQueue默认是允许退出的。 消息入队 MessageQueue的消息入队方法是enqueueMessage,改方法在Handler里的enqueueMessage方法里调用。  boolean enqueueMessage(Message msg, long when) {         #判断入队消息对象的handler是否存在,不存在抛出异常         if (msg.target == null) {             throw new IllegalArgumentException("Message must have a target.");         }         #判断消息是否正在使用(消息队列里或回收池里),使用的话抛出异常         if (msg.isInUse()) {             throw new IllegalStateException(msg + " This message is already in use.");         }         synchronized (this) {             if (mQuitting) { #正在退出,回首消息并返回false                 IllegalStateException e = new IllegalStateException(                         msg.target + " sending message to a Handler on a dead thread");                 Log.w(TAG, e.getMessage(), e);                 msg.recycle();                 return false;             }          #消息标记成使用中状态             msg.markInUse();             msg.when = when;             Message p = mMessages;             boolean needWake;             #当前队列头部消息是空,或者when是0(代表立即执行),或执行的时间小于当前队首执行的时间,则把该消息放到队首 … Read more

Anroid Handler原理-Message

    Message翻译过来是消息,顾名思义,在Android中它定义了一个消息体,消息包含了描述和任意的数据对象,可以被发送给Handler。Message对象包含了两个int类型的额外字段,也包含一个object类型的额外字段,可以在多种情况下不分配。 尽管Message的构造器是public类型的,但最好的获取Message对象的方法是调用Message.obtain()方法或者Handler.obtainMessage()方法,这将会从对象回收池中拉取对象。 享元模式(FlyWeight) 享元模式是23种Gof设计模式结构化模式的一种,它在处理大量具有简单重复元素,单独存储会使用大量内存的时候非常有用,通常做法是把共享的数据存储在外部的数据结构里面,使用的时候把他们传递给对象。 Handler.obtainMessage方法内部也是调用的Message.obtain,所以只看后者:  public static final Object sPoolSync = new Object();     private static Message sPool;     private static int sPoolSize = 0; #当前消息池的大小     ….     ….     private static final int MAX_POOL_SIZE = 50;  #缓存消息池最大容量   public static Message obtain() {         synchronized (sPoolSync) {             if (sPool != null) {                 Message m = sPool;                 sPool = m.next;                 m.next = null;                 m.flags = 0; // clear in-use flag                 sPoolSize–;                 return m;             }         }         return new Message();     }     sPool如果是空,则new一个新的Message,非空的话从缓存池获取对象,并清空获取到的Message对象的flags,消息池当前大小减1。此外Message还有几个重载的obtain方法,分别对应不同场景对Message对象设置不同的属性,本质上都是从缓存池拿对象。 消息回收 Message回收共有两个方法,回收就是把Message对象放在全局的回收池,两个方法分别是: recycleUnchecked() /**      * Recycles a Message that may be in-use.回收一个可能在使用的消息      * Used internally by the MessageQueue and Looper when disposing of queued Messages.处理完队列消息时在MessageQueue和Looper内部使用       */     @UnsupportedAppUsage     void recycleUnchecked() {         // Mark the message as in use while it remains in the recycled object pool.         // Clear out all other details.清空其他的详细信息         flags = FLAG_IN_USE;         what = 0;         arg1 = 0;         arg2 = 0;         obj = null;         replyTo = null;         sendingUid = UID_NONE;         workSourceUid = UID_NONE;         when = 0;         target = null;         callback = null;         data = null;             synchronized (sPoolSync) {             if (sPoolSize < MAX_POOL_SIZE) {              #缓存池对象小于50,当前缓存池后移,当前对象放在链表首部,缓存池大小加一                 next = sPool;                 sPool = this;                 sPoolSize++; … Read more

Android Studio Arctic Fox 原生项目集成Flutter模块Failed to apply plugin class ‘FlutterPlugin’

今天升级Android Studio Arctic Fox Patch2后,新建Android原生项目,并在原生项目工程上新建Flutter module,编译无法通过,报错信息: Caused by: org.gradle.api.internal.plugins.PluginApplicationException:  Failed to apply plugin class 'FlutterPlugin'.   Caused by: org.gradle.api.InvalidUserCodeException:  Build was configured to prefer settings repositories over project repositories but repository 'maven'  was added by plugin class 'FlutterPlugin' 谷歌了半天没有找到解决方法,只好自己一步步慢慢解决,最终找到了解决方式。 根据报错信息,应该是在构建Flutter module的时候出的问题,大体意思是构建过程被配置为更喜欢settings里的仓库,而不是project里面的仓库,但是仓库maven通过FlutterPlugin添加了。 打开Android原生工程的settings.gradle文件,对比发现通过Arctic Fox创建的项目,settings.gradle多了这些配置信息: dependencyResolutionManagement {     repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)     repositories {         google()         mavenCentral()         jcenter() // Warning: this repository is going to shut down soon     } } 根据gradle文档描述,DependencyResolutionManagement是gradle6.8之后新增的配置项,它为构建的所有工程配置依赖解析 RepositoriesMode配置在构建中仓库如何设置,总共有三种方式: FAIL_ON_PROJECT_REPOS 表示如果工程单独设置了仓库,或工程的插件设置了仓库,构建就直接报错抛出异常 PREFER_PROJECT 表示如果工程单独设置了仓库,就优先使用工程配置的,忽略settings里面的 PREFER_SETTINGS 表述任何通过工程单独设置或插件设置的仓库,都会被忽略 到这里,综合报错信息就豁然开朗了,原来是因为settings.gradle里配置了FAIL_ON_PROJECT_REPOS,而Flutter插件又单独设置了repository,所以会构建报错,所以我直接把FAIL_ON_PROJECT_REPOS改成PREFER_PROJECT,再重新build,接下来又有报错信息了,大致信息如下: Execution failed for task ':app:mergeDebugResources'. > Could not resolve all files for configuration ':app:debugRuntimeClasspath'.    > Could not find org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30.      Searched in the following locations:        – https://storage.flutter-io.cn/download.flutter.io/org/jetbrains/kotlin/kotlin-stdlib-jdk8/        1.5.30/kotlin-stdlib-jdk8-1.5.30.pom        … 原来都所有依赖库都按找flutter module里面配置的仓库下载依赖了,打开Android工程目录下的build.gradle,添加下面的配置: allprojects {     repositories {         google()         jcenter()     } } 然后sync,重新build,成功了!顺手给stackoverflow提交了一个回答~: PluginApplicationException: Failed to apply plugin … Read more

Flutter 集成到现有的安卓原生项目中-集成方式

Flutter可以作为Gradle子工程或AAR文件嵌入到现有的安卓原生项目中,集成流程可以使用Android Studio的插件或手动集成,从Flutter v1.26开始,支持在原生项目中集成多个Flutter引擎、screen,view的实例。 注意:你的原生安卓项目可能支持mips或x86架构,Flutter目前(2021年9月)只支持AOT模式编译x86_64,armabi-v7a,arm64-v8a 可以在app上使用abiFilters安卓Gradle插件api限制支持的架构,避免缺少libflutter.so造成的运行时异常,比如: android {   //…   defaultConfig {     ndk {       // Filter for architectures supported by Flutter.       abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86_64'     }   } } Flutter引用有x86和x86——64版本,当使用模拟器JIT模式调试时,Flutter模块会正确的运行。 用Android Studio集成 Android Studio自动集成Flutter module是非常方便的,可以在项目中同时编辑android原生代码和Flutter代码,并可以继续使用Flutter插件,比如Dart代码自动补全,hot reload,widget检查等。 添加到app的流程支持Android Studio 3.6,42+的IntelliJ Flutter插件,Android Studio集成也只支持使用源码gradle子项目集成,而不支持使用AAR. 使用Android Studio菜单栏的File>New>New Module…,你可以创建一个新的Flutter module集成,或者选择一个之前创建的Flutter module Android Studio插件会自动配置Android工程,添加Flutter module作为依赖。 手动集成 手动集成Flutter module到安卓项目,不使用Android studio插件,按照如下步骤: 创建一个Module 假设我们有一个Android app在 some/path/MyApp 路径,我们想要我们的Flutter 工程在同级目录 cd some/path/ flutter create -t module –org com.adamin flutter_m3 这样会在some/path/flutter_m3目录下创建一个Flutter module,里面有一些Dart代码作为你的初始代码,还有个.android的隐藏文件夹,.android文件夹包含一个android项目,它既可以帮助你通过flutter run命令单独运行flutter模块,也是一个包装器,可以帮助将Flutter模块引导为可嵌入的android 库。 Java 8 需求 Flutter Android … Read more

Java必备基础知识备忘整理

8大数据类型 byte/8 char/16 short/16 int/32 float/32 long/64 double/64 boolean/~ new Integer(2333)和 Integer.valueOf(2333)区别 使用new关键字创建每次都会创建一个新对象,而使用Integer.valueOf会从缓存池获取引用对象,没有才会去创建 String JDK1.8和1.9的区别 Jdk1.8和之前版本String使用char数组存储,1.9及之后使用byte数组和coder标识编码类型实现 String不可变的好处 1.缓存hash值  2.String pool需要   3.安全性(网络传输)  4.线程安全 String StringBuffer StringBuilder对比 可变性方面: String不可变,StringBuffer和StringBuilder可变  线程安全方面: String和StringBuffer安全,StringBuffer内部使用sychronized关键字同步,StringBuilder不安全 final关键字修饰的数据,方法,类 修饰数据: 对于基本数据类型,使用final关键字修饰后不可改变 对于引用类型,引用本身不能被改变,也就是不能指向其他对象,但是引用的对象本身内部可以改变。 修饰方法: 使用final修饰的方法不能被子类重写 修饰类: 类不允许被继承 浅拷贝和深拷贝 浅拷贝拷贝的对象和原始对象引用同一个对象,拷贝对像改变也会改变原始对象 深拷贝拷贝对象和原始对象应用不同对象, 泛型类型擦除 Java中泛型的工作原理是类型擦除,编译器在编译时会擦除类型相关信息,运行时不存在类型相关信息 泛型中的限定通配符和非限定通配符 限定通配符有两种: <? extend T> 指定泛型的上界,必须是T类型的子类 <? super T> 指定泛型下界,类型必须是T类型的父类 非限定通配符: <?> 可以是任意类型 equals的五大特性 自反性: x.equals(x) ==true;  x非空 对称性: x.equals(y)==true 则 y.equals(x)==true x,y非空 传递性: if(x.equals(y)&&y.equals(z)) 则 x.equals(z)==true  x,y,z非空 一致性: 多次调用x.equals(y)返回值始终一致 非空性: 对任意非空x,x.equals(null) 始终返回false Java集合Collection Set 无重复序列  TreeSet 底层使用TreeMap存储,而TreeMap底层使用红黑树,有序,查找时间复杂度O(logN)  HashSet 无需,可以实现快速查找,底层实现是哈希表,查找的时间复杂度O(1)  LinkedHashSet,有HashSet的查找速度,内部使用双向链表维护顺序 List 可以有重复数据  ArrayList基于动态数组实现,所以可以随机访问  Vector,和ArrayList类似,但是线程安全  LinkedList,基于双向链表实现,顺序访问,插入删除速度快,可以用作栈,队列,双向队列 … Read more

数据结构基础-链表

数据结构基础-链表(linked list) 链表在数据结构中通常用来实现其他的数据结构,它是一个节点序列,其中每个节点存储自己的数据和指向下一个节点位置的指针(地址),可以被想象成一个链接链: 列表中最后一项有一个指向NULL的链接,表示链的结尾。 优点(与数组对比) 尽管链表有点像数组,但是它不限制声明元素的长度 数组需要把数据存储在连续的内存或者磁盘上,链表不需要 链表插入和移除元素更高效,不需要重新分配和组织整个,因为数据不需要连续存储 缺点 不允许随机访问,访问数据必须第一个开始遍历,因为没法办用链表实现二分查找 需要额外的内存空间指向链接 链表通常用作构建其他数据结构的基本模块,比如栈,队列,树,图。 链表的细分类型 单链表 链表中每个元素都指向下一个元素,最后一个元素指向空 环形链表 链表中每个元素都指向下一个元素,最后一个元素指向第一个 双向链表 链表中每个元素都指向下一个元素,也指向上一个元素,首个元素的向上指向空,最后一个元素向下指向空 双向环形链表 跟双向链表类似,但是首个元素向上指向最后一个,最后一个向下指向第一个 Java实现的简单的双向链表 /** * java 实现双向链表demo */public class DoubleLinkedList {    class Node{        Node prev;        int data;        Node next;        public Node(int data) { … Read more

flutter2接入高德地图定位,工具类封装,打包安卓apk,自定义签名

flutter 接入高德地图,打包安卓apk,自定义签名 引入依赖 在pubspec.yaml引入 amap_flutter_location: ^2.0.0 依赖,然后执行 pub get Android 生成签名文件 在项目android/app 目录下打开终端输入 keytool -genkey -v -keystore xipingflutter.jks -keyalg RSA -keysize 2048 -validity 10000 -alias xiping 然后根据依次设置密钥,姓名,单位,组织,地区,别名密钥等: 输入密钥库口令:再次输入新口令:您的名字与姓氏是什么?  [Unknown]:  adam您的组织单位名称是什么?  [Unknown]:  xiping您的组织名称是什么?  [Unknown]:  xiping您所在的城市或区域名称是什么?  [Unknown]:  cn您所在的省/市/自治区名称是什么?  [Unknown]:  cn该单位的双字母国家/地区代码是什么?  [Unknown]:  CNCN=adam, OU=xiping, O=xiping, L=cn, ST=cn, C=CN是否正确?  [否]:  是正在为以下对象生成 2,048 位RSA密钥对和自签名证书 (SHA256withRSA) (有效期为 10,000 天):         CN=adam, OU=xiping, O=xiping, L=cn, ST=cn, C=CN输入 <xiping> 的密钥口令     … Read more