Sunday, December 30, 2018
Java目录
Java 8
Stream API, Optional API, 跟CompletableFuture
lang3
EqualsBuilder
ToStringBuilder
Google Guava (Google Collections Library)
ImmutableSet.of
ImmutableMap.of
Java的Null pointer exception
Java中的ThreadLocal和弱引用
ORM:
lombok
Database ORM:
MyBatis
JSON:
fasterxml
Build tool:
Gradle简介
Saturday, December 15, 2018
NTLK
NTLK主要用于比较两文档的相似度
https://my.oschina.net/Samyan/blog/1796944
https://my.oschina.net/Samyan/blog/1796944
Tuesday, November 6, 2018
Cucumber简介
Cucumber是平实语言版的unit test,可用于包层次的测试。优势在于它允许非程序员参与,需求更加明确。
测试方法:
https://www.cnblogs.com/TankXiao/archive/2012/02/20/2347016.html
BDD/Functional test framwork: Cucumber
TDD:
https://cucumber.io/
Gherkin
plain text语音来描述unit test中的arrange(mock), act, assert。
例子
Scenario: Breaker guesses a word
Given the Maker has chosen a word
When the Breaker makes a guess
Then the Maker is asked to score
测试方法:
https://www.cnblogs.com/TankXiao/archive/2012/02/20/2347016.html
BDD/Functional test framwork: Cucumber
TDD:
https://cucumber.io/
Gherkin
plain text语音来描述unit test中的arrange(mock), act, assert。
例子
Scenario: Breaker guesses a word
Given the Maker has chosen a word
When the Breaker makes a guess
Then the Maker is asked to score
Friday, October 26, 2018
Gradle简介
Gradle与Maven比较:
1. Gradle利用cache使得build过程更快
2. Gradle利用分块build(incremental),也就是指对修改的文件重新build,如修改了test,只build该test
https://gradle.org/maven-vs-gradle/
https://www.jianshu.com/p/00d5469e25e7
1. Gradle利用cache使得build过程更快
2. Gradle利用分块build(incremental),也就是指对修改的文件重新build,如修改了test,只build该test
https://gradle.org/maven-vs-gradle/
https://www.jianshu.com/p/00d5469e25e7
Thursday, October 18, 2018
Java的Null pointer exception
Boolean a;
boolean b = false || a;
会出现NPE因为a可能为null。
switch(a){
case true:
return "";
}
会出现NPE因为a可能为null。
boolean b = false || a;
会出现NPE因为a可能为null。
switch(a){
case true:
return "";
}
会出现NPE因为a可能为null。
Friday, September 21, 2018
Java中的ThreadLocal和弱引用
ThreadLocal就是线程的私有变量和对象
static ThreadLocal<Metric> metric = new ThreadLocal<>();
这里用static因为相当于线程的私有全局变量,避免数据的重复copy(不同实例)。但可能导致内存泄漏(因为static不会被回收)。如果有线程池,线程会被复用就减低内存泄漏的可能。
https://www.zhihu.com/question/35250439
Strong ref是Map m = new HashMap();
Soft Ref内存不足才会回收,适用于缓存
Week Reference是回收器自动回收弱引用对象(HashMap中)
Phantom Ref是在析构finalize中不会复活下回收弱引用
https://droidyue.com/blog/2016/03/13/learning-threadlocal-in-java/
https://droidyue.com/blog/2014/10/12/understanding-weakreference-in-java/
我的书目:
static ThreadLocal<Metric> metric = new ThreadLocal<>();
这里用static因为相当于线程的私有全局变量,避免数据的重复copy(不同实例)。但可能导致内存泄漏(因为static不会被回收)。如果有线程池,线程会被复用就减低内存泄漏的可能。
https://www.zhihu.com/question/35250439
Strong ref是Map m = new HashMap();
Soft Ref内存不足才会回收,适用于缓存
Week Reference是回收器自动回收弱引用对象(HashMap中)
Phantom Ref是在析构finalize中不会复活下回收弱引用
https://droidyue.com/blog/2016/03/13/learning-threadlocal-in-java/
https://droidyue.com/blog/2014/10/12/understanding-weakreference-in-java/
我的书目:
Effective Java中文版(第2版)
Java并发编程实战
深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)
重构:改善既有代码的设计
系统思维:复杂商业系统的设计之道(原书第3版)
Sunday, September 9, 2018
JS代码缺陷自动分析工具 - eslint
eslint
gulp: js build tool
node.js
webpack: web browser library
unit test: Mocha
http://www.ruanyifeng.com/blog/2015/12/a-mocha-tutorial-of-examples.html
gulp: js build tool
node.js
webpack: web browser library
unit test: Mocha
http://www.ruanyifeng.com/blog/2015/12/a-mocha-tutorial-of-examples.html
Thursday, August 16, 2018
whistle简介
如何安装
http://wproxy.org/whistle/install.html
https设置
http://wproxy.org/whistle/webui/https.html
http://wproxy.org/whistle/install.html
https设置
http://wproxy.org/whistle/webui/https.html
windows commands
netstat -ano | findstr :8899
taskkill /PID typeyourPIDhere /F
https://stackoverflow.com/questions/39632667/how-to-kill-a-currently-using-port-on-localhost-in-windows
taskkill /PID typeyourPIDhere /F
https://stackoverflow.com/questions/39632667/how-to-kill-a-currently-using-port-on-localhost-in-windows
Thursday, June 28, 2018
AWS CloudFront
CDN service
比如Alexa use case,可以用于给一个skill播放音乐,用CloudFront根据user location来读取相应地区的audio。CloudFront自动配对到S3.
Monday, June 25, 2018
AWS EMR简介
AWS EMR是基于Hadoop来做数据计算的平台。比如Log analysis,用log来抽取结构化数据,上传到S3, Redshift可以从S3读取文件,EMR作用相当于ETL运算机器。
Monday, April 16, 2018
JavaScript Plugin Design pattern
Summary
https://stackoverflow.com/questions/10763006/plugin-architecture-in-web-apps-examples-or-code-snippets
Command
http://www.dofactory.com/javascript/command-design-pattern
var calculator = new Calculator();
// issue commands
calculator.execute(new AddCommand(100));
calculator.execute(new SubCommand(24));
calculator.execute(new MulCommand(6));
calculator.execute(new DivCommand(2));
Callback
https://www.w3schools.com/jquery/jquery_callback.asp
slow之后callback函数:
$("button").click(function(){
$("p").hide("slow", function(){
alert("The paragraph is now hidden");
});
});
Dependency Injection
https://github.com/nikku/didi
有点似Factory pattern,根据不同的输入(car)来决定load哪个object。
Abstract Factory
http://www.dofactory.com/javascript/abstract-factory-design-pattern
var persons = [];
var employeeFactory = new EmployeeFactory();
var vendorFactory = new VendorFactory();
persons.push(employeeFactory.create("Joan DiSilva"));
persons.push(employeeFactory.create("Tim O'Neill"));
Builder
http://www.dofactory.com/javascript/builder-design-pattern
var shop = new Shop();
var carBuilder = new CarBuilder();
var truckBuilder = new TruckBuilder();
var car = shop.construct(carBuilder);
var truck = shop.construct(truckBuilder);
Others
https://seesparkbox.com/foundry/api_patterns_for_your_open_source_javascript_plugin
Ref
Youtube player APIs: https://developers.google.com/youtube/iframe_api_reference
Android lifecycle: https://developer.android.com/guide/components/activities/activity-lifecycle
Android MediaPlayer State Diagram: https://developer.android.com/reference/android/media/MediaPlayer
Alexa
AVS: 怎么用Alexa来做事,如audio player天气预报,交通情况。这是比较generic的,无skill
Smart Home API: 怎么创建一个SH的skill,比较有针对性,AVS不包括的。
Video API: 同上
https://stackoverflow.com/questions/10763006/plugin-architecture-in-web-apps-examples-or-code-snippets
Command
http://www.dofactory.com/javascript/command-design-pattern
var calculator = new Calculator();
// issue commands
calculator.execute(new AddCommand(100));
calculator.execute(new SubCommand(24));
calculator.execute(new MulCommand(6));
calculator.execute(new DivCommand(2));
Callback
https://www.w3schools.com/jquery/jquery_callback.asp
slow之后callback函数:
$("button").click(function(){
$("p").hide("slow", function(){
alert("The paragraph is now hidden");
});
});
Dependency Injection
https://github.com/nikku/didi
有点似Factory pattern,根据不同的输入(car)来决定load哪个object。
var Car = function(engine) { this.start = function() { engine.start(); }; }; var createPetrolEngine = function(power) { return { start: function() { console.log('Starting engine with ' + power + 'hp'); } }; }; // a module is just a plain JavaScript object // it is a recipe for the injector, how to instantiate stuff var module = { // if an object asks for 'car', the injector will call new Car(...) to produce it 'car': ['type', Car], // if an object asks for 'engine', the injector will call createPetrolEngine(...) to produce it 'engine': ['factory', createPetrolEngine], // if an object asks for 'power', the injector will give it number 1184 'power': ['value', 1184] // probably Bugatti Veyron }; var di = require('di'); var injector = new di.Injector([module]); injector.invoke(function(car) { car.start(); });
Abstract Factory
http://www.dofactory.com/javascript/abstract-factory-design-pattern
var persons = [];
var employeeFactory = new EmployeeFactory();
var vendorFactory = new VendorFactory();
persons.push(employeeFactory.create("Joan DiSilva"));
persons.push(employeeFactory.create("Tim O'Neill"));
Builder
http://www.dofactory.com/javascript/builder-design-pattern
var shop = new Shop();
var carBuilder = new CarBuilder();
var truckBuilder = new TruckBuilder();
var car = shop.construct(carBuilder);
var truck = shop.construct(truckBuilder);
Others
https://seesparkbox.com/foundry/api_patterns_for_your_open_source_javascript_plugin
Ref
Youtube player APIs: https://developers.google.com/youtube/iframe_api_reference
Android lifecycle: https://developer.android.com/guide/components/activities/activity-lifecycle
Android MediaPlayer State Diagram: https://developer.android.com/reference/android/media/MediaPlayer
Alexa
AVS: 怎么用Alexa来做事,如audio player天气预报,交通情况。这是比较generic的,无skill
Smart Home API: 怎么创建一个SH的skill,比较有针对性,AVS不包括的。
Video API: 同上
Wednesday, April 11, 2018
Token简介
Token是什么?
Token是访问某些资源的凭证。打个比喻,我想进入某个公司的办公室,token就是badge,办公室就是我想访问的资源。
为什么需要token?
Token是一个加密字符串,是被访问资源发给客户端的凭证。用户第一次登录给出用户名和密码,之后获得token,以后每次访问均只需要给出token即可,而不需要再登录。资源服务器只要验证token即可。这机制避免了每访问一次都要发密码的需要,从而大大降低密码被截获的可能性。Token实质上是密码的一个替代,但不带任何用户信息。这叫opaque string(不透明),表示一般人不理解,但它对应着用户id。
Refresh token和access token的区别
Refresh token就是上述描述的token,由资源服务器发出,同时资源服务器也会将其保留在DB中。客户登录即获得此token保存在本地存储比如Android的sqlite。当每次需要访问资源就会发出带此token的request,服务器会进行验证。Refresh token不会过期(比如手机上的微信,永远不用重新登录),这会导致一个问题,就是资源服务器没办法revoke或修改这个权限。为了支持动态更改访问权限,引入access token。access token才是真正访问资源的token,它具有较短的有效期(大多数一小时),保证权限大多数情况下最新且更为安全。
Refresh token和access token的关系
htt分用户登录时候,就会即时获得refresh token和access token,每次访问资源用到access token,当access token过期时候,客户端会用refresh token去获得新的access token,同时也会获得新的refresh token。资源服务器也会更新DB中refresh token。access token含有client id的信息,若access token被盗取(compromised)(比如user id和access token不一致,因为黑客试图随意产生access token来骗资源服务器),客户服务器会删除DB中的refresh token,这样access token过期后便不能访问资源,客户端需要重新登录。资源服务器通过access token授权给单一客户端a single authenticated client。例如,用另一个手机登录微信,原手机就会被迫退出并提示安全风险。
资源服务器架构
一般而言,资源服务器含有Auth server和resource server,分别用于验证和提供资源。刚才提到的所有理论都是来自于Auth server。
登录的request
$ curl -X POST -H 'Authorization: Basic dGVzdGNsaWVudDpzZWNyZXQ=' -d 'grant_type=password&username=test&password=test' localhost:3000/oauth/token
{
"token_type":"bearer",
"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiVlx1MDAxNcKbwoNUwoonbFPCu8KhwrYiLCJpYXQiOjE0NDQyNjI1NDMsImV4cCI6MTQ0NDI2MjU2M30.MldruS1PvZaRZIJR4legQaauQ3_DYKxxP2rFnD37Ip4",
"expires_in":20,
"refresh_token":"fdb8fdbecf1d03ce5e6125c067733c0d51de209c"
}
更新access token的request
curl -X POST -H 'Authorization: Basic dGVzdGNsaWVudDpzZWNyZXQ=' -d 'refresh_token=fdb8fdbecf1d03ce5e6125c067733c0d51de209c&grant_type=refresh_token' localhost:3000/oauth/token
{
"token_type":"bearer",
"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiVlx1MDAxNcKbwoNUwoonbFPCu8KhwrYiLCJpYXQiOjE0NDQyNjI4NjYsImV4cCI6MTQ0NDI2Mjg4Nn0.Dww7TC-d0teDAgsmKHw7bhF2THNichsE6rVJq9xu_2s",
"expires_in":20,
"refresh_token":"7fd15938c823cf58e78019bea2af142f9449696a"
}
Token是访问资源的凭证。比如Hulu想发events给A公司,Amazon公司就需要给Hulu一个token。这里的token叫LWA token (Login with Amazon)。又如,vtasters提供FB login,FB就给vtasters一个access token取访问FB的资源,当然第一次用FB login时候,会出现一个页面告知用户哪些FB信息(例如生日)会被vtasters访问。这叫scope,是能访问资源的范围,这种给予第三方的token权限一般比第一方的权限低。
OAuth token
refresh token(never expire) refresh tokens have a very long duration (month to unlimited) and are stored at the client in a persistent storage (e.g. database or filesystem)
bearer token=access token(an hour): user's permission scope
correlation token: A token that identifies the message exchange. map to 用户id
LWA token: amazon第三方token
MAP token: amazon第一坊token
auth token key
怎么防止篡改token
要求token的时候,加入一个client secret加密的字符串即可,验证此request是否来自于官方的app。这个client secret只有client app和server知道。所以通过这个方法就可以验证token request是否被篡改,如client assertion和用户名密码一起发送获取access token。client assertion又叫JWT(json web token)就是用client key对一些字段进行加密发到server端,它有一套工业标准。
curl -X POST -H 'Authorization: B
Token的历史
API keys
Google maps用的就是API key,只要从Google获取,每次request加入key即可访问。
用户场景:公司内部应用,不需访问与用户相关的数据。
OAuth Token
第三方Facebook Login. 用户需同意第三方可访问FB的scope获refresh/access token。对比与API keys,好处是限定访问资源范围,会过期减少资源不法访问的可能,access token可以revoke(删除其在数据库的记录)。
Json web token
OAuth token的进化版,客户端对字符串进行加密,server端进行验证。可避免数据库查找access token。
用户场景:减少数据库访问,且不需要立即revoke token。
Page token:
Page token与start index。page token是该search搜索结果的该页的最后一个item的hash,这样获取下一页的时候就可以知道从哪开始。好处是即使有新收据加入,获取下一页的时候也有可能得到。坏处是只能按顺序获取,也就是不能从一页跳到第10页,所以用于Infinite scrolling.
Ref:
https://stackoverflow.com/questions/25838183/what-is-the-oauth-2-0-bearer-token-exactly
https://auth0.com/learn/refresh-tokens/
https://jwt.io/
https://mozillazg.com/2015/06/hello-jwt.html
https://zapier.com/engineering/apikey-oauth-jwt/
Page token作用
Token是访问某些资源的凭证。打个比喻,我想进入某个公司的办公室,token就是badge,办公室就是我想访问的资源。
为什么需要token?
Token是一个加密字符串,是被访问资源发给客户端的凭证。用户第一次登录给出用户名和密码,之后获得token,以后每次访问均只需要给出token即可,而不需要再登录。资源服务器只要验证token即可。这机制避免了每访问一次都要发密码的需要,从而大大降低密码被截获的可能性。Token实质上是密码的一个替代,但不带任何用户信息。这叫opaque string(不透明),表示一般人不理解,但它对应着用户id。
Refresh token和access token的区别
Refresh token就是上述描述的token,由资源服务器发出,同时资源服务器也会将其保留在DB中。客户登录即获得此token保存在本地存储比如Android的sqlite。当每次需要访问资源就会发出带此token的request,服务器会进行验证。Refresh token不会过期(比如手机上的微信,永远不用重新登录),这会导致一个问题,就是资源服务器没办法revoke或修改这个权限。为了支持动态更改访问权限,引入access token。access token才是真正访问资源的token,它具有较短的有效期(大多数一小时),保证权限大多数情况下最新且更为安全。
Refresh token和access token的关系
htt分用户登录时候,就会即时获得refresh token和access token,每次访问资源用到access token,当access token过期时候,客户端会用refresh token去获得新的access token,同时也会获得新的refresh token。资源服务器也会更新DB中refresh token。access token含有client id的信息,若access token被盗取(compromised)(比如user id和access token不一致,因为黑客试图随意产生access token来骗资源服务器),客户服务器会删除DB中的refresh token,这样access token过期后便不能访问资源,客户端需要重新登录。资源服务器通过access token授权给单一客户端a single authenticated client。例如,用另一个手机登录微信,原手机就会被迫退出并提示安全风险。
资源服务器架构
一般而言,资源服务器含有Auth server和resource server,分别用于验证和提供资源。刚才提到的所有理论都是来自于Auth server。
登录的request
$ curl -X POST -H 'Authorization: Basic dGVzdGNsaWVudDpzZWNyZXQ=' -d 'grant_type=password&username=test&password=test' localhost:3000/oauth/token
{
"token_type":"bearer",
"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiVlx1MDAxNcKbwoNUwoonbFPCu8KhwrYiLCJpYXQiOjE0NDQyNjI1NDMsImV4cCI6MTQ0NDI2MjU2M30.MldruS1PvZaRZIJR4legQaauQ3_DYKxxP2rFnD37Ip4",
"expires_in":20,
"refresh_token":"fdb8fdbecf1d03ce5e6125c067733c0d51de209c"
}
更新access token的request
curl -X POST -H 'Authorization: Basic dGVzdGNsaWVudDpzZWNyZXQ=' -d 'refresh_token=fdb8fdbecf1d03ce5e6125c067733c0d51de209c&grant_type=refresh_token' localhost:3000/oauth/token
{
"token_type":"bearer",
"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiVlx1MDAxNcKbwoNUwoonbFPCu8KhwrYiLCJpYXQiOjE0NDQyNjI4NjYsImV4cCI6MTQ0NDI2Mjg4Nn0.Dww7TC-d0teDAgsmKHw7bhF2THNichsE6rVJq9xu_2s",
"expires_in":20,
"refresh_token":"7fd15938c823cf58e78019bea2af142f9449696a"
}
Token是访问资源的凭证。比如Hulu想发events给A公司,Amazon公司就需要给Hulu一个token。这里的token叫LWA token (Login with Amazon)。又如,vtasters提供FB login,FB就给vtasters一个access token取访问FB的资源,当然第一次用FB login时候,会出现一个页面告知用户哪些FB信息(例如生日)会被vtasters访问。这叫scope,是能访问资源的范围,这种给予第三方的token权限一般比第一方的权限低。
OAuth token
refresh token(never expire) refresh tokens have a very long duration (month to unlimited) and are stored at the client in a persistent storage (e.g. database or filesystem)
bearer token=access token(an hour): user's permission scope
correlation token: A token that identifies the message exchange. map to 用户id
LWA token: amazon第三方token
MAP token: amazon第一坊token
auth token key
怎么防止篡改token
要求token的时候,加入一个client secret加密的字符串即可,验证此request是否来自于官方的app。这个client secret只有client app和server知道。所以通过这个方法就可以验证token request是否被篡改,如client assertion和用户名密码一起发送获取access token。client assertion又叫JWT(json web token)就是用client key对一些字段进行加密发到server端,它有一套工业标准。
headers = json.dumps({ "typ" : "JWT", "alg" : "HS256" }) claims = json.dumps({ "iss": "mozillazg.com", "exp": 1435055117, "user_id": 1, "foo": "bar" }) content = base64url_encode(headers) + '.' + base64url_encode(claims) secret_key = 'your secret key' signature = hmac.new(secret_key, content, hashlib.sha256).digest() token = content + '.' + base64url_encode(signature)
curl -X POST -H 'Authorization: B
Token的历史
API keys
Google maps用的就是API key,只要从Google获取,每次request加入key即可访问。
用户场景:公司内部应用,不需访问与用户相关的数据。
OAuth Token
第三方Facebook Login. 用户需同意第三方可访问FB的scope获refresh/access token。对比与API keys,好处是限定访问资源范围,会过期减少资源不法访问的可能,access token可以revoke(删除其在数据库的记录)。
Json web token
OAuth token的进化版,客户端对字符串进行加密,server端进行验证。可避免数据库查找access token。
用户场景:减少数据库访问,且不需要立即revoke token。
Page token:
Page token与start index。page token是该search搜索结果的该页的最后一个item的hash,这样获取下一页的时候就可以知道从哪开始。好处是即使有新收据加入,获取下一页的时候也有可能得到。坏处是只能按顺序获取,也就是不能从一页跳到第10页,所以用于Infinite scrolling.
Ref:
https://stackoverflow.com/questions/25838183/what-is-the-oauth-2-0-bearer-token-exactly
https://auth0.com/learn/refresh-tokens/
https://jwt.io/
https://mozillazg.com/2015/06/hello-jwt.html
https://zapier.com/engineering/apikey-oauth-jwt/
Page token作用
Friday, March 23, 2018
HTML5 video player
<!DOCTYPE html>
<html>
<body>
<button onclick="playVid()" type="button">Play</button>
<button onclick="pauseVid()" type="button">Pause</button>
<button onclick="seekVid()" type="button">Seek</button>
<button onclick="ccVid()" type="button">CC</button><br>
<video id="myVideo" width="600" height="400" autoplay="autoplay" controls='false'>
<source src="./big.mp4" type="video/mp4">
<track label="pt" kind="subtitles" srclang="pt" src="./small.vtt" default />
Your browser does not support the video tag.
</video>
<script>
var vid = document.getElementById("myVideo");
var aaaa = 'showing';
function myFunction() {
document.getElementById("myVideo").controls = true;
}
function playVid() {
vid.play();
}
function pauseVid() {
vid.pause();
}
function seekVid() {
var cTime = vid.currentTime;
vid.currentTime += 3;
}
function ccVid() {
if (aaaa==='showing')
aaaa = 'hidden';
else
aaaa = 'showing';
for (var i = 0; i < vid.textTracks.length; i++)
vid.textTracks[i].mode = aaaa;
}
</script>
</body>
</html>
<html>
<body>
<button onclick="playVid()" type="button">Play</button>
<button onclick="pauseVid()" type="button">Pause</button>
<button onclick="seekVid()" type="button">Seek</button>
<button onclick="ccVid()" type="button">CC</button><br>
<video id="myVideo" width="600" height="400" autoplay="autoplay" controls='false'>
<source src="./big.mp4" type="video/mp4">
<track label="pt" kind="subtitles" srclang="pt" src="./small.vtt" default />
Your browser does not support the video tag.
</video>
<script>
var vid = document.getElementById("myVideo");
var aaaa = 'showing';
function myFunction() {
document.getElementById("myVideo").controls = true;
}
function playVid() {
vid.play();
}
function pauseVid() {
vid.pause();
}
function seekVid() {
var cTime = vid.currentTime;
vid.currentTime += 3;
}
function ccVid() {
if (aaaa==='showing')
aaaa = 'hidden';
else
aaaa = 'showing';
for (var i = 0; i < vid.textTracks.length; i++)
vid.textTracks[i].mode = aaaa;
}
</script>
</body>
</html>
Monday, March 12, 2018
Android之webview
1. webview的基本代码
https://developer.android.com/guide/webapps/webview.htmlwebview.xml:
<?xml version="1.0" encoding="utf-8"?>
<WebView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/webView1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
MainActivity.java:
public class MainActivity extends Activity {
private WebView webView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.webview);
webView = (WebView) findViewById(R.id.webView1);
webView.setJavaScriptEnabled(true);
webView.loadUrl("http://www.vtasters.com/unittest");
//webView.loadUrl("file:///android_asset/abc.html");//in app/assets/abc.html
AndroidManifest.xml:
<manifest ... >
<uses-permission android:name="android.permission.INTERNET" />
...
</manifest>
2. JS和webview交互
http://mthli.github.io/Android-WebView-JavaScript需要准备一个网站如vtasters,webview可以通过loadUrl来执行对应功能。
public class MyWebView extends WebView {
public MyWebView(Context context) {
...
getSettings().setJavaScriptEnabled(true);
addJavascriptInterface(this, "MyName");
...
}
@JavascriptInterface
public void example() {
...
}
}
Sunday, February 25, 2018
Protobuf协议
http://blog.csdn.net/antgan/article/details/52103966
解码:
http://yura415.github.io/js-protobuf-encode-decode/
解码:
http://yura415.github.io/js-protobuf-encode-decode/
Subscribe to:
Posts (Atom)