文章目录
前面讲解方法,结尾放代码
首先需要一个WebView
/*查找到WebView控件*/
mWebView = (WebView) findViewById(R.id.webView);
/*给WebView一个H5的链接,这里使用的是自己启动的Vue项目*/
mWebView.loadUrl("http://10.20.58.190:8081/");
/*对WebView进行设置*/
WebSettings webSettings = mWebView.getSettings();
/*既然要调用H5的方法,那么一定不能禁用JS方法*/
webSettings.setJavaScriptEnabled(true);
android方法:
/*在某处写入这一行代码即可*/
mWebView.loadUrl("javascript:test1Fun('使用这种方法无法取得返回参数,且会刷新页面,如果js函数有返回值,则页面会仅展示返回值')");
需要H5支持:
/*
这里使用的是Vue,对data里的test1Content 进行了修改
*/
test1Fun(str){
this.test1Content = str;
// return "调用test1Fun成功";
}
/*
要注意的是,如果使用原生H5,直接在页面的JavaScript标签里写入一个方法即可
但是如果使用vue来写的话,需要将此方法暴露给window,如下
*/
mounted(){
window.test1Fun = this.test1Fun;
}
这种方法比较简单,但是缺点在于android无法获取函数的返回值
注:如果调用的函数存在返回值的话,那么H5的页面会只显示返回值
android方法:
mWebView.evaluateJavascript("test2Fun('使用这种方法可以取得返回参数,且不会刷新页面')", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
text2.setText(value);
}
});
这种方法同样需要H5支持,同上:
test2Fun(str){
this.test2Content = str;
return "调用test2Fun成功";
}
/*同样需要暴露到window*/
mounted(){
window.test2Fun = this.test2Fun;
}
这种方法比上一种方法更为灵活,且能够获取返回值
android注入:
/*将JsInteration注入到h5的window.android中*/
mWebView.addJavascriptInterface(new JsInteration(), "android");
/*这里实现JsInteration */
public class JsInteration {
@JavascriptInterface
public String JsCallJava1(String value) {
text3.setText(value);
return "调用JsCallJava1成功";
}
}
H5调用:
useJsCallJava1(){
let a = window.android.JsCallJava1("我是JsCallJava1的返回值");
this.JsCallJava1Content = a;
}
这种方式运用最为广泛,一些企业级的项目都是以此为基础搭建H5调用android的桥方法,当然,为了防止注入过多的方法,参数一般是JSON字符串格式,在android获取到参数后,会将其转换为JSON,然后根据其状态,进行后续的操作反馈。
android方法:
/*这里的url是H5将要进行跳转的链接,使用这个方法进行拦截*/
mWebView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.equals("http://10.20.58.190:8081/intercept")) {
text4.setText("intercept");
// startActivity(new Intent(MainActivity.this,SecondFragment.class));
return true;
} else {
mWebView.loadUrl(url);
return false;
}
}
});
H5调用:
location.href = "http://10.20.58.190:8081/intercept";
注:这里一般是用于拦截链接,如果shouldOverrideUrlLoading的返回值为true,则会进行拦截,H5不进行跳转,否则则进行跳转
android方法:
mWebView.setWebChromeClient(new WebChromeClient(){
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result){
if (message.equals("alert")){
alert.setText("成功");
}
return super.onJsAlert(view, url, message, result);
}
@Override
public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
if (message.equals("confirm")){
confirm.setText("成功");
}
return super.onJsConfirm(view, url, message, result);
}
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
if (message.equals("prompt")){
prompt.setText("成功");
}
return super.onJsPrompt(view, url, message, defaultValue, result);
}
});
H5触发:
useJsCallJava3(judge){
if(judge == 1){
alert('alert')
}
if(judge == 2){
confirm('confirm')
}
if(judge == 3){
prompt('prompt')
}
}
此方法将会监听三种弹窗,用户可以根据弹窗内容进行判断,但是请注意
如果在android拦截后,return了true,则会默认客户会对弹窗进行处理,所以我们要对弹窗进行额外处理,否则H5页面就会卡死。
因此这种方法为了避免麻烦,还是少用为好,并且不对弹窗进行拦截,仅监听即可。
最后,完整的demo如下
MainActivity.java:
package com.example.study_android_java_javascript;
import android.os.Bundle;
import android.view.View;
import android.webkit.JavascriptInterface;
import android.webkit.JsPromptResult;
import android.webkit.JsResult;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
public static final String TAG = "MainActivity";
private WebView mWebView;
private TextView text1;
private TextView text2;
private TextView text3;
private TextView text4;
private Button btn1;
private Button btn2;
private Button btn_clear;
private TextView alert;
private TextView confirm;
private TextView prompt;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text1 =findViewById(R.id.text1);
text2 =findViewById(R.id.text2);
text3 = findViewById(R.id.text3);
text4 = findViewById(R.id.text4);
alert = findViewById(R.id.alert);
confirm = findViewById(R.id.confirm);
prompt = findViewById(R.id.prompt);
btn1 = (Button) findViewById(R.id.btn1);
btn1.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view) {
mWebView.loadUrl("javascript:test1Fun('使用这种方法无法取得返回参数,且会刷新页面,如果js函数有返回值,则页面会仅展示返回值')");
}
});
btn2 = (Button) findViewById(R.id.btn2);
btn2.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view) {
mWebView.evaluateJavascript("test2Fun('使用这种方法可以取得返回参数,且不会刷新页面')", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
text2.setText(value);
}
});
}
});
btn_clear = findViewById(R.id.btn_clear);
btn_clear.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view) {
mWebView.loadUrl("javascript:clearContent()");
text2.setText("暂无返回");
}
});
mWebView = (WebView) findViewById(R.id.webView);
mWebView.loadUrl("http://10.20.58.190:8081/");
WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
mWebView.addJavascriptInterface(new JsInteration(), "android");
mWebView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.equals("http://10.20.58.190:8081/intercept")) {
text4.setText("intercept");
// startActivity(new Intent(MainActivity.this,SecondFragment.class));
return true;
} else {
mWebView.loadUrl(url);
return false;
}
}
});
mWebView.setWebChromeClient(new WebChromeClient(){
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result){
if (message.equals("alert")){
alert.setText("成功");
}
return super.onJsAlert(view, url, message, result);
}
@Override
public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
if (message.equals("confirm")){
confirm.setText("成功");
}
return super.onJsConfirm(view, url, message, result);
}
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
if (message.equals("prompt")){
prompt.setText("成功");
}
return super.onJsPrompt(view, url, message, defaultValue, result);
}
});
}
//Android调用有返回值js方法
public class JsInteration {
@JavascriptInterface
public String JsCallJava1(String value) {
text3.setText(value);
return "调用JsCallJava1成功";
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center_horizontal">
<WebView
android:layout_width="match_parent"
android:layout_height="200dp"
android:id="@+id/webView"
/>
<Button
android:id="@+id/btn1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:text="使用webview.loadUrl()调用JavaScript方法"/>
<TextView
android:id="@+id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="暂无返回"/>
<TextView
android:layout_width="match_parent"
android:layout_height="20dp"/>
<Button
android:id="@+id/btn2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:text="使用webview.evaluateJavascript()调用JS方法"/>
<TextView
android:id="@+id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="暂无返回"/>
<Button
android:id="@+id/btn_clear"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:text="清除H5的内容"
android:layout_marginTop="20dp"/>
<TextView
android:layout_marginTop="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="JavaScript调用Java方法:"/>
<TextView
android:id="@+id/text3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="JsCallJava1返回值"/>
<TextView
android:layout_marginTop="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="拦截链接:"/>
<TextView
android:id="@+id/text4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="拦截测试数据"/>
<TextView
android:layout_marginTop="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="拦截弹窗"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="alert:"/>
<TextView
android:id="@+id/alert"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="confirm:"/>
<TextView
android:id="@+id/confirm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="prompt:"/>
<TextView
android:id="@+id/prompt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""/>
</LinearLayout>
</LinearLayout>
indexVue.vue
<template>
<div class="box">
<div class="test1">
<h3 title="123">{{test1}}</h3>
<h4>测试内容:{{test1Content}}</h4>
</div>
<div class="test2">
<h3>{{test2}}</h3>
<h4>测试内容:{{test2Content}}</h4>
</div>
<button @click="useJsCallJava1">调用Java方法:JsCallJava1</button>
<h4>返回数据:{{JsCallJava1Content}}</h4>
<button @click="useJsCallJava2">拦截链接</button>
<h4> </h4>
<button @click="useJsCallJava3(1)">测试拦截alert</button>
<button @click="useJsCallJava3(2)">测试拦截confirm</button>
<button @click="useJsCallJava3(3)">测试拦截prompt</button>
</div>
</template>
<script>
export default {
data(){
return {
test1:"Java使用webview.loadUrl()调用JavaScript方法",
test1Content:"",
test2:"Java使用webview.evaluateJavascript()调用JavaScript方法",
test2Content:"",
JsCallJava1Content:"",
};
},
methods:{
test1Fun(str){
this.test1Content = str;
// return "调用test1Fun成功";
},
test2Fun(str){
this.test2Content = str;
return "调用test2Fun成功";
},
clearContent(){
this.test1Content = "";
this.test2Content = "";
},
useJsCallJava1(){
let a = window.android.JsCallJava1("我是JsCallJava1的返回值");
this.JsCallJava1Content = a;
},
useJsCallJava2(){
location.href = "intercept";
},
useJsCallJava3(judge){
if(judge == 1){
alert('alert')
}
if(judge == 2){
confirm('confirm')
}
if(judge == 3){
prompt('prompt')
}
}
},
mounted(){
window.test1Fun = this.test1Fun;
window.test2Fun = this.test2Fun;
window.clearContent = this.clearContent;
}
}
</script>
<style scoped>
h3{
color: blue;
}
h4{
color: red;
}
</style>
我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
我正在尝试设置一个puppet节点,但rubygems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由rubygems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby
我想了解Ruby方法methods()是如何工作的。我尝试使用“ruby方法”在Google上搜索,但这不是我需要的。我也看过ruby-doc.org,但我没有找到这种方法。你能详细解释一下它是如何工作的或者给我一个链接吗?更新我用methods()方法做了实验,得到了这样的结果:'labrat'代码classFirstdeffirst_instance_mymethodenddefself.first_class_mymethodendendclassSecond使用类#returnsavailablemethodslistforclassandancestorsputsSeco
我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer
设置:狂欢ruby1.9.2高线(1.6.13)描述:我已经相当习惯在其他一些项目中使用highline,但已经有几个月没有使用它了。现在,在Ruby1.9.2上全新安装时,它似乎不允许在同一行回答提示。所以以前我会看到类似的东西:require"highline/import"ask"Whatisyourfavoritecolor?"并得到:Whatisyourfavoritecolor?|现在我看到类似的东西:Whatisyourfavoritecolor?|竖线(|)符号是我的终端光标。知道为什么会发生这种变化吗? 最佳答案
我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby1.9+ 关于ruby-主要:Objectwhenrun
我有一个具有一些属性的模型:attr1、attr2和attr3。我需要在不执行回调和验证的情况下更新此属性。我找到了update_column方法,但我想同时更新三个属性。我需要这样的东西:update_columns({attr1:val1,attr2:val2,attr3:val3})代替update_column(attr1,val1)update_column(attr2,val2)update_column(attr3,val3) 最佳答案 您可以使用update_columns(attr1:val1,attr2:val2
我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)