【转】Android WebView设置代理及账号密码

转载自:Android WebView设置代理及账号密码


一.背景

很多小伙伴都会遇到公司的app需要通过外网访问公司的内网服务,这个时候后台同学就会配置一个代理服务器,app通过代理服务器访问公司内网。出于安全的考虑,还会对访问代理服务器的请求进行身份验证。

那么Android的WebView如何设置代理,之前查了下网上的资料,大多是通过反射进行设置,但是Google官方已经提供了方便的API供我们使用了。所以,下面就简单介绍下WebView的代理的设置。

二.具体步骤

Android WebView设置代理需要使用ProxyConfig相关类,身份验证需要在WebViewClient的onReceivedHttpAuthRequest里进行。
首先,我们在项目的build.gradle添加相关依赖。

implementation 'androidx.webkit:webkit:1.3.0'

设置代理具体代码如下:

private void init() {
    wv = findViewById(R.id.wv);
    WebSettings webSettings = wv.getSettings();
    webSettings.setSupportZoom(true);
    webSettings.setJavaScriptEnabled(true);
    wv.setWebViewClient(new WebViewClient() {
        @Override
        public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm){
            //身份验证(账号密码)
            handler.proceed("userName", "password");
        }
    });
    setProxy();
    wv.loadUrl("http://www.uc123.com");
}

private void setProxy() {
    if (WebViewFeature.isFeatureSupported(WebViewFeature.PROXY_OVERRIDE)) {
        ProxyConfig proxyConfig = new ProxyConfig.Builder()
                .addProxyRule("111.123.321.121:1234")
                .addDirect().build();
        ProxyController.getInstance().setProxyOverride(proxyConfig, new Executor() {
            @Override
            public void execute(Runnable command) {
                //do nothing
            }
        }, new Runnable() {
            @Override
            public void run() {
                Log.w(TAG, "WebView代理改变");
            }
        });
    }
}

【转】安卓webview加载网页实现网页翻译

转载自:安卓webview加载网页实现网页翻译


前言

说下应用场景,最近安卓要加载一些第三方网站进行用户的开放使用,这些第三方网站基本都是全英文的外国网站,于是产品需求希望能对网站进行中文翻译,类似pc浏览器的谷歌翻译网页

使用步骤

1.注入脚本

代码如下(示例):

private void translateWeb() {
        String javaScript = "javascript:function appendScrip() {" +
                "var head= document.getElementsByTagName('head')[0]; var script= document.createElement('script'); script.src= 'https://res.zvo.cn/translate/translate.js'; head.appendChild(script);" +
                "}" +
                "appendScrip();";
        bwvContent.evaluateJavascript(javaScript, new ValueCallback() {
            @Override
            public void onReceiveValue(String s) {
                MyLogUtils.e("javaScript.onReceiveValue:" + s);
                bwvContent.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        if (bwvContent==null) {
                            return;
                        }
                        String javaScript2 = "javascript:function startTranslate() {" +
                                "translate.localLanguage='zh-CN';translate.selectLanguageTag.show = false;translate.executeByLocalLanguage();" +
                                "}" +
                                "startTranslate();";
                        bwvContent.evaluateJavascript(javaScript2, new ValueCallback() {
                            @Override
                            public void onReceiveValue(String s) {
                                MyLogUtils.e("javaScript2.onReceiveValue:" + s);
                            }
                        });
                    }
                }, 500);
            }
        });
    }

注意点

1.这里的bwvContent用的是腾讯的webview,在执行注入脚本的时候用的evaluateJavascript方法,原生webview如果没有的话用loadurl也可

2.第一段脚本注入和第二段脚本注入加了个500ms的延时操作,因为实测过程中,连续执行的情况下容易没能顺利进行翻译,所以加了个500ms加高成功率,可自行调试测试

3.该方法的注入,选择时机放在了onProgressChanged回调里,当加载进度progress==100时,进行延时1000ms后执行该方法做自动网页翻译,或者由用户手动点击翻译按钮的时候调用,时机的选择自行调试

使用的注入脚本的相关链接:网页多语言翻译 js v1.2,更新翻译接口 – OSCHINA – 中文开源技术交流社区

Android使用ViewPager2实现画廊效果

1.ViewPager2和父布局添加 android:clipChildren=”false” 属性

2.ViewPager2左右两侧增加Margin

3.ViewPager2的OffscreenPageLimit设置为大于等于1的值

binding.viewPager.setOffscreenPageLimit(1);

4.ViewPager2设置PageTransformer

binding.viewPager.setPageTransformer(new GalleryTransformer());
import android.view.View;

import androidx.viewpager2.widget.ViewPager2;

public class GalleryTransformer implements ViewPager2.PageTransformer {
    public static float MIN_ALPHA = 0.8f;
    public static float MIN_SCALE = 0.8f;

    @Override
    public void transformPage(View page, float position) {
        if (position < -1 || position > 1) {
            page.setAlpha(MIN_ALPHA);
            page.setScaleX(MIN_SCALE);
            page.setScaleY(MIN_SCALE);
        } else if (position <= 1) { // [-1,1]
            float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
            float scaleX;
            if (position < 0) {
                scaleX = 1 + 0.1f * position;
            } else {
                scaleX = 1 - 0.1f * position;
            }
            page.setScaleX(scaleX);
            page.setScaleY(scaleX);
            page.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA));
        }
    }
}

参考资料:

Android使用ViewPager2中遇到的问题(使用ViewPager2实现画廊效果)

万能ViewPager2适配器–SmartViewPager2Adapter

安卓渐变色状态栏

节选自:Android实现状态栏(statusbar)渐变效果的示例 (有改动)


private View statusBarView;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
      getWindow().getDecorView().addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
        @Override
        public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
          initStatusBar();
        }
      });
  }
  private void initStatusBar() {
    if (statusBarView == null) {
      int identifier = getResources().getIdentifier("statusBarBackground", "id", "android");
      statusBarView = getWindow().findViewById(identifier);
    }
    if (statusBarView != null) {
        statusBarView.setBackgroundResource("你的渐变drawable资源id");
    }
  }

【转】Android 端 Rsa加密数据

转载自:Android 端 Rsa加密数据


1.android 端加密方式

  • 非对称加密 (RSA)
  • 对称加密 (DES,AES,3DES)
  • MD5加密
  • BASE64编码

ps:这篇主要介绍android rsa加密

2.Rsa加密原理

1.随机选择两个大质数p和q,p不等于q,计算N=pq;

2.选择一个大于1小于N的自然数e,e必须与(p-1)(q-1)互素。

3.用公式计算出d:d×e = 1 (mod (p-1)(q-1)) 。

4.销毁p和q。

最终得到的N和e就是“公钥”,d就是“私钥”,发送方使用N去加密数据,接收方只有使用d才能解开数据内容。

3.Rsa相比对称加密算法优缺点

优点:

  • 对称加密比对称加密算法更安全

缺点:

  • 加密速度更慢,适用于加密少量数据

4.示例 (公钥加密,私钥解密)

通过公钥字符串 获取PublicKey对象

byte[] buffer = Base64Utils.decode(publicKeyStr);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
RSAPublicKey publicKey = (RSAPublicKey) RSAPublicKey.generatePublic(keySpec);

使用publickey加密数据

Cipher cipher = Cipher.getInstance("转换");
// 编码前设定编码方式及密钥
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
// 传入编码数据并返回编码结果
byte[] encrptData = cipher.doFinal(data);

几个关键参数介绍:

1.转换 是一个字符串,它描述为产生某种输出而在给定的输入上执行的操作(或一组操作); 形式可以是 算法/模式/填充 或 算法; 常见的模式如下:

RSA (如果你的明文不够128字节加密的时候会在你的明文前面,前向的填充零。解密后的明文也会包括前面填充的零,这是服务器需要注意把解密后的字段前向填充的零去掉,才是真正之前加密的明文。)

RSA/ECB/PKCS1Padding (加密的时候会在你的明文中随机填充一些数据,所以会导致对同样的明文每次加密后的结果都不一样)

RSA/None/PKCS1Padding

第一个 RSA 等价于 RSA/None/NoPadding .使用此模式加密后 同一个明文、同一个公钥每次生成同一个密文.攻击者能够据此识别到同一个信息都是何时被发送。 所以一般使用第二个 RSA/ECB/PKCS1Padding .

2.编码方式设定

cipher.init(MODE, publicKey);

常见编码方式 (MODE):

ENCRYPT_MODE: Cipher 初始化为加密模式的常量 (常用)

DECRYPT_MODE: Cipher 初始化为解密模式的常量 (常用)

WRAP_MODE :Cipher 初始化为密钥包装模式的常量

UNWRAP_MODE :Cipher 初始化为密钥解包模式的常量

PUBLIC_KEY :解包的密钥为“公钥”的常量

PRIVATE_KEY : 解包的密钥为“私钥”的常量

SECRET_KEY :解包的密钥为“秘密密钥”的常量

5.开发过程中容易遇到的坑

1.客户端需要与后端确认好使用同一转换模式 做到一一对应. 如果后端(java使用 RSA),则前端 需要使用(RSA/ECB/PKCS1Padding) 而不是 RSA.

2.前端请求下来的公钥字符串如果 包含 “—–BEGIN PUBLIC KEY—–” 和 “—–END PUBLIC KEY—–“,需要将其切掉,如果直接使用 会报 InvalidKeySpecException .