标签: canvas

为什么两个 android App 执行同一个 js,执行结果不同

问下各位 Android 大佬, 为什么两个 android App 执行同一个 js,执行结果不同!

 

Jione · 2 天前 · 1658 次点击

问下各位 Android 大佬, 为什么两个 android App 执行同一个 js,执行结果不同! 我用手机浏览器画的 canvas 转 base64 用 A app 执行 js 画 canvas 转 base64 没问题和浏览器画的一致 用 B app 执行 js 画 canvas 转 base64 和浏览器不一致

执行 js 是用的同样的代码!

17 条回复    2021-10-18 10:28:28 +08:00

Jione
    1

Jione   2 天前

问下各位 Android 大佬, 为什么两个 android App 执行同一个 js,执行结果不同!
我用手机浏览器画的 canvas 转 base64
用 A app 执行 js 画 canvas 转 base64 没问题和浏览器画的一致
用 B app 执行 js 画 canvas 转 base64 和浏览器不一致

执行 js 是用的同样的代码!

fugui2
    2

fugui2   2 天前

show your code
Jione
    3

Jione   1 天前

@fugui2 应该不是 js 代码和调用 js 的这个代码问题吧,
MonkeyD1
    4

MonkeyD1   1 天前

webview 的内核版本不同? webkit 版本内核 之类的
InDom
    5

InDom   1 天前

之前有个 利用 Canvas 画板计算用户指纹来识别跟踪用户。
Jione
    6

Jione   1 天前

@MonkeyD1 都对比了是一样的
Jione
    7

Jione   1 天前

@InDom 对我是正在做这个,但是不知道两个同样的 app 执行两个同样的代码结果不一样
stardust21
    8

stardust21   1 天前

原因应该就是 4 楼说的,不同的 APP 用了不同的 webview 内核
deplivesb
    9

deplivesb   1 天前   ❤️ 3

到现在也没见到代码,全靠广大网友猜
又一个悬丝诊脉
damao2250
    10

damao2250   1 天前

悬丝诊脉
Jione
    11

Jione   1 天前

@stardust21 两个 app 的运行 js 代码
String js = “”;
try {
InputStream is = null;
is = getAssets().open(“main.js”);
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
js = new String(buffer);

} catch (IOException e) {
e.printStackTrace();
}
JsEvaluator jsEvaluator = new JsEvaluator(this);

jsEvaluator.callFunction(js,
new JsCallback() {
@Override
public void onResult(String result) {
// Process result here.
// This method is called in the UI thread.
MyLog.loge(“result:”+result);
MyLog.log(“md5:” + md5(result));
}
@Override
public void onError(String errorMessage) {
MyLog.log(“errorMessage:” + errorMessage);

// Process JavaScript error here.
// This method is called in the UI thread.
}
}, “webglFp”);

Jione
    12

Jione   1 天前

@deplivesb 代码已发
WebKit
    13

WebKit   1 天前 via Android

手机版本?还是说同一个手机装的两个 app ?如果是国内的 app,可以试试卸载腾讯系软件,然后卸载重装这两个 app 试试
ruri
    14

ruri   1 天前

webview 你就别指望不同设备执行结果会一样了,这也是为什么现在很多 APP 会集成腾讯 x5 的主要原因,就是为了让自己的 APP 在每个设备上运行结果相同,减少开发调试精力。
其实较新版本的谷歌官方或 AOSP webview 都没什么毛病,但你架不住有些国内厂商会魔改自己手机系统里的 webview,哪怕是微调一些 webview 的默认参数,都会导致你的代码运行效果和原版大不一样。
lisongeee
    15

lisongeee   20 小时 56 分钟前

@Jione 你发的是 java 代码,还有 js 代码呢?
zoharSoul
    16

zoharSoul   18 小时 22 分钟前

@Jione 要的是 js 代码, Java 代码有啥好看的
Jione
    17

Jione   2 小时 35 分钟前

@ruri 两个 app 都是我自己的 app ,没有集成其他内核

android_浅析canvas的save()和restore()方法

android_浅析canvas的save()和restore()方法

  1. <span style=“font-size:18px;”> </span>  
  1. <span style=“font-size:18px;”></span>   

绘图之前,首先需要调整画笔,待画笔调整好之后,再将图像绘制到画布上,这样才可以显示在手机屏幕上!Android 中的画笔是 Paint类,Paint 中包含了很多方法对其属性进行设置,主要常用方法:

setAntiAlias: 设置画笔的锯齿效果。
setColor: 设置画笔颜色
setARGB:  设置画笔的a,r,p,g值。
setAlpha:  设置Alpha值
setTextSize: 设置字体尺寸。
setStyle:  设置画笔风格,空心或者实心。
setStrokeWidth: 设置空心的边框宽度。
getColor:  得到画笔的颜色
getAlpha:  得到画笔的Alpha值。

自定义控件时常常遇到重写View的Ondraw()方法,Ondraw()方法常常设计到save()和restore()这两个方法

,现结合demo简单分析一下这两个方法的作用:

 

1.save():用来保存Canvas的状态,save()方法之后的代码,可以调用Canvas的平移、放缩、旋转、裁剪等操作!

2.restore():用来恢复Canvas之前保存的状态,防止save()方法代码之后对Canvas执行的操作,继续对后续的绘制会产生影响,通过该方法可以避免连带的影响!

 

通过一个例子说明一下:

例如:我们想在画布上绘制一个向右的三角箭头,当然,我们可以直接绘制,另外,我们也可以先把画布旋转90°,画一个向上的箭头,然后再旋转回来(这种旋转操作对于画圆周上的标记非常有用),*后,我们在右下角绘一个20像素的圆!

 

代码:

  1. <span style=“font-size:18px;”>package com.test.ui;  
  2. import android.R.color;  
  3. import android.content.Context;  
  4. import android.graphics.Canvas;  
  5. import android.graphics.Color;  
  6. import android.graphics.Paint;  
  7. import android.view.View;  
  8. public class GameView extends View  {  
  9.     public final static String TAG = “Example_05_03_GameView”;  
  10.     // 声明Paint对象  
  11.     private Paint mPaint = null;  
  12.     public GameView(Context context) {  
  13.         super(context);  
  14.         mPaint = new Paint();  
  15.     }
  16.     @Override  
  17.     protected void onDraw(Canvas canvas) {  
  18.         super.onDraw(canvas);  
  19.         Paint background=new Paint();  
  20.         Paint line=new Paint();  
  21.         background.setColor(color.darker_gray);
  22.         line.setColor(Color.RED);
  23.         int px = getMeasuredWidth();  
  24.         int py = getMeasuredWidth();  
  25.         // Draw background  
  26.         canvas.drawRect(0, 0, px, py, background);  
  27.         canvas.save();
  28.         canvas.rotate(90, px/2, py/2);                  
  29.          //画一个向上的箭头  
  30.         canvas.drawLine(px / 2, 0, 0, py / 2, line); //左边的斜杠        
  31.         canvas.drawLine(px / 2, 0, px, py / 2, line);//右边的斜杠  
  32.         canvas.drawLine(px / 2, 0, px / 2, py, line);//垂直的竖杠  
  33.         canvas.restore();
  34.         // Draw circle  
  35.         canvas.drawCircle(px – 10, py – 10, 10, line);   
  36.     }
  37. }
  38. </span>

 

MainActivity.Java:

 

  1. <span style=“font-size:18px;”>package com.test.ui;  
  2. import android.app.Activity;  
  3. import android.os.Bundle;  
  4. public class MainActivity extends Activity {  
  5.     private GameView mGameView;  
  6.     @Override  
  7.     public void onCreate(Bundle savedInstanceState) {  
  8.         super.onCreate(savedInstanceState);  
  9.         setContentView(R.layout.activity_main);
  10.         mGameView = new GameView(this);  
  11.         setContentView(mGameView);
  12.     }
  13. }
  14. </span>

运行结果:

 

%title插图%num

 

如果将 canvas.save()和canvas.restore()注释掉,那么圆点将会随着之前的90旋转跑到了左边,没有达到你预期想要显示在右下角的效果:

 

%title插图%num

 

以上我们很明显看到圆圈位置的明显差异。不进行Canvas的save和restore操作的话,所有的图像都是在画布旋转90°后的画布上绘制的。当执行完onDraw方法,系统自动将画布恢复回来。save和restore操作执行的时机不同,就能绘制不同的图形,save和restore之间,往往是对Canvas的特殊操作!

 

 

android clipRect Op.xxx各个参数理解

有点小啰嗦的一篇学习笔记,可以直接看*后得出的结论:前面的各种图片和说明都是为*后的结论服务的

1)剪切:和平常画图工具剪切的作用一样,在画布上剪切一个区域,比如剪切一个Rect区域,画布canvas其余的部分都丢掉,之后所有的画图都在这个Rect区域内进行(如果不涉及save和restore方法)。

2)clip进行剪切的时候,不会影响之前已经画好的图形。

3)剪切是对canvas的操作,而不是在canvas上的图进行操作。

为了说明这几点,下面进行一下说明。

步骤1) 在剪切之前绘制一个全屏的蓝色的矩形。

2)定义剪切的矩形Rect区域,并进行剪切

3)设置剪切过后画布颜色为红色

运行的效果如下图所示:此时剪切过后画布的区域就是剪切的Rect区域,虽然剪切掉了canvas上面和下面的一部分,但是仍然会把途中所示的蓝色部分显示出来而不会剪切掉:也就是如上所说不会影响之前已经画好的图形。

%title插图%num

 

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
protected void onDraw(Canvas canvas) {
        int width = getMeasuredWidth();
        int height = getMeasuredHeight();
        
        
        Paint paint = new Paint();
        paint.setColor(Color.BLUE);    
        //全屏绘制一个蓝色的矩形画面
        canvas.drawRect(0, 0,width,height,paint);
    
        //定义剪切的Rect区域
        Rect rect = new Rect();
        rect.left = 0;
        rect.top = 300;//左上角(0,300)
        rect.right = width;
        rect.bottom = height/2; //右下角(width,height)
        //进行剪切   
        canvas.clipRect(rect)
        canvas.drawColor(Color.RED);
     
    }

上面的clipRect是只有一个参数的(默认为INTERSECT,下面看看它的重载方法Cliprect(rect,OP.xx)第二个参数以及各个参数的含义和运行效果:

开始之前做些准备工作:

区域A:剪切之前的画布区域

区域B:当前要剪切的区域,也就是clipRect的*个参数所表示的区域

在没有直接写代码测试之前对这些字段的翻译和查阅写数学资料并对Op.xxx的各种字段在心里做了如下假设:

XOR:异或运算,相同为0(false),不用为1(true),也就是两个区域重叠的地方为0,不同的地方为1,剪切过后的画布的区域就是两个区域不重叠的部分。

INTERSECT:交集运算,剪切过后的画布区域就是两个区域的交集区域。

REPLACE:这个有待验证,不明所以,从字面意思来说是代替的意思,应该就是用B的区域代替A的区域,所以剪切过后的画布区域可能就是只剩下B的区域,当然这个只是假设,有待下面的验证过。

DIFFERENCE:差集运算,剪切过后的画布的区域就是A-B

REVERSE_DIFFERENCE:差集运算,REVERSE为反向,逆向的意思,不难猜出剪切过后的画布区域是B-A的区域

UNION:并集运算,剪切过后的画布区域就是A和B的区域相加,当然重叠的地方只计算一次

下面就写程序注意验证上面的结果和得出相应的结论

先是全集和子集的情况:此时A为全集区域,B为A的子集

%title插图%num

a) Op.DIFFERENCE:即将剪切的区域(设置B)与当前canvas(设置A)之间的差集,剪切过后还剩下的画布canvas区域就是A-B的区域,看看运行结果

步骤还是之前的步骤,只是把canvas.clipRect(rect)改成canvas.clipRect(rect,Op.DIFFERENCE);运行结果如下:<喎�”/kf/ware/vc/” target=”_blank” class=”keylink”>vcD4KPHA+PGltZyBzcmM9″/uploadfile/Collfiles/20150212/2015021208423342.png” alt=”\”>

b) Op.REVERSE_DIFFERENCE:对比DIFFERENCE取A-B,REVERSE是相反的意思,所以为B-A,因为B为A的子集,所以该差集不存在,所以运行结果为下:

%title插图%num

c) Op.XOR:两个区域进行异或运算,异或运算的规则是:“相同为0(false),不同为1(true)”,当两个区域进行异或的时候,很显然“区域重叠的地方为0,不重叠的地方为1”,剪切过后剩下的画布canvas的区域就是不重叠的地方所在的区域,看看运行结果

%title插图%num

d) Op.UNION 取A和B的并集,所以运行结果为下图:

%title插图%num

 

e) Op.INTERSECT 取A和B的交集,因为上面的程序中A是全屏的画布范围,而B在A里面,所以剪切的结果为下图所示,所以说交集为B的范围

%title插图%num

f) Op.REPLACE,运行效果如下

%title插图%num

通过全集和子集的运行效果来看,REPLACE应该就是跟上面设想的一样,其余的倒是跟设想的结论一样。

所以我就测试了非全集和子集的情况

此时A区域和B区域的关系如图,C为A和B的交集区域:

%title插图%num

测试画图步骤:

1)绘制一个蓝色的矩形面

2)定义A的Rect对象(*次要剪切的区域),并开始剪切

3)定义B的rect对象并开始剪切,并且调用clipRect(rect,Op.xxx)来看不用xxx下剪切的效果

4)把剪切过后的画布设置为红色

上面步骤的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
                int width = 1000;
                int height =1000;
                Paint paint = new Paint();
        paint.setColor(Color.BLUE);    
        //全屏绘制一个蓝色的矩形画面
        canvas.drawRect(0, 0,width,height,paint);
        
              //定义区域A的rect对象
        Rect rect = new Rect();
        rect.left =100;
        rect.top = 100;//左上角(0,300)
        rect.right = 300;
        rect.bottom = 300; //右下角(width,hei
        //剪切为A区域
        canvas.clipRect(rect);//同clipRect
        
                //设置b的rect对象
        rect.left =200;
        rect.top = 200;//左上角(0,300)
        rect.right = 400;
        rect.bottom = 400; //右下角(width,height) 
        canvas.clipRect(rect,Op.xxxx);
                //把剪切过后的画布设置红色
                canvas.drawColor(Color.RED);

 

a) DIFFERENCE的情况下的运行效果(A-B的差集):也就是A区域去掉C区域

%title插图%num

b) REVERSE_DIFFERENCE的运行效果如下图(B-A的差集):也就是B区域去掉C区域

%title插图%num

c) UNION 的运行结果 (A和B的并集)

%title插图%num

d) INTERSECT (交集运算)此时画布只剩下C区域可以显示,所以运行结果如下

%title插图%num

e)XOR 异或运算,剪切过后的结果为A和B区域不重叠的区域

%title插图%num

f)REPLACE 这个运算结果是什么呢?就是B区域,也就是剪切过后的结果只保留B区域,这也就是REPLACE代替或者替换的含义:当前还没被剪切的区域A被即将要剪切的区域B来代替。

%title插图%num

结论:

XOR:异或运算,相同为0(false),不用为1(true),也就是两个区域重叠的地方为0,不同的地方为1,剪切过后的画布的区域就是两个区域不重叠的部分。

INTERSECT:交集运算,剪切过后的画布区域就是两个区域的交集区域。

DIFFERENCE:差集运算,剪切过后的画布的区域就是A-B

REVERSE_DIFFERENCE:差集运算,REVERSE为反向,逆向的意思,不难猜出剪切过后的画布区域是B-A的区域

UNION:并集运算,剪切过后的画布的区域为A+B的区域

REPLACE:也就是剪切过后的结果只保留B区域,这也就是REPLACE代替或者替换的含义:当前还没被剪切的区域A被即将要剪切的区域B来代替。

在线文档 App 的表格布局,一般都用哪个库?

腾讯文档、飞书这类在线文档 App 的表格布局,一般都是用哪个库?还是都是原生手写的布局?

试了下原生手写的<TableLayout>和<TableRow>的控制,比较麻烦,效果还不好。不知道大厂这些在线文档的表格,一般是用那个库实现的?还是真的要手写?

 

14 条回复    2021-02-06 12:31:23 +08:00
youxiachai
    1

youxiachai   69 天前

好像都是 canvas 自己画的吧?
bojue
    2

bojue   69 天前

canvas 绘制的,一般使用的可能是 wps 或者 spreadjs 的 sdk,腾讯好像是自研
wang93wei
    3

wang93wei   69 天前

腾讯文档快把我坑死了,,,

用啥功能啥功能报错。而且动不动文档就打不开了。

腾讯质量控制就这么差吗?

hqtc
    4

hqtc   69 天前

语雀*好了
liudaqi
    5

liudaqi   69 天前

@hqtc #4 语雀没有原生 Android 客户端。
kealm
    6

kealm   69 天前

SpreadJS
itskingname
    7

itskingname   69 天前

@hqtc 语雀*近在我电脑上一直闪退。macOS
liudaqi
    8

liudaqi   69 天前

@bojue
@kealm

SpreadJS 有 安卓版 SDK 吗?还是须要用 webview 去实现?

coffeedeveloper
    9

coffeedeveloper   69 天前

@itskingname #7 可以去语雀讨论区提供一下相关信息,会有对应的人员帮忙排查一下的。
Jeb
    10

Jeb   69 天前   ❤️ 1

问了下在飞书前端的朋友,内嵌 web,自研绘图引擎。
zpxshl
    11

zpxshl   69 天前 via Android

wps 好像是原生写的,真牛逼
YongkeLi
    12

YongkeLi   69 天前

一直在用腾讯文档 挺好用的呀
DiamondYuan
    13

DiamondYuan   68 天前 via iPhone

https://tool.lu/index.php/en_US/deck/qo/detail?slide=25

钉钉的分享

kealm
    14

kealm   61 天前

用 WebView,语雀、飞书等多多少少都有 SpreadJS 的影子,虽然现在说自研,但肯定是参考了 SpreadJS 的源码(是的,源码可以买到)。
友情链接: SITEMAP | 旋风加速器官网 | 旋风软件中心 | textarea | 黑洞加速器 | jiaohess | 老王加速器 | 烧饼哥加速器 | 小蓝鸟 | tiktok加速器 | 旋风加速度器 | 旋风加速 | quickq加速器 | 飞驰加速器 | 飞鸟加速器 | 狗急加速器 | hammer加速器 | trafficace | 原子加速器 | 葫芦加速器 | 麦旋风 | 油管加速器 | anycastly | INS加速器 | INS加速器免费版 | 免费vqn加速外网 | 旋风加速器 | 快橙加速器 | 啊哈加速器 | 迷雾通 | 优途加速器 | 海外播 | 坚果加速器 | 海外vqn加速 | 蘑菇加速器 | 毛豆加速器 | 接码平台 | 接码S | 西柚加速器 | 快柠檬加速器 | 黑洞加速 | falemon | 快橙加速器 | anycast加速器 | ibaidu | moneytreeblog | 坚果加速器 | 派币加速器 | 飞鸟加速器 | 毛豆APP | PIKPAK | 安卓vqn免费 | 一元机场加速器 | 一元机场 | 老王加速器 | 黑洞加速器 | 白石山 | 小牛加速器 | 黑洞加速 | 迷雾通官网 | 迷雾通 | 迷雾通加速器 | 十大免费加速神器 | 猎豹加速器 | 蚂蚁加速器 | 坚果加速器 | 黑洞加速 | 银河加速器 | 猎豹加速器 | 海鸥加速器 | 芒果加速器 | 小牛加速器 | 极光加速器 | 黑洞加速 | movabletype中文网 | 猎豹加速器官网 | 烧饼哥加速器官网 | 旋风加速器度器 | 哔咔漫画 | PicACG | 雷霆加速