<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Android &#8211; 编程技术记录</title>
	<atom:link href="https://blog.z6z8.cn/category/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/android/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.z6z8.cn</link>
	<description>世界你好!</description>
	<lastBuildDate>Mon, 22 Mar 2021 02:00:16 +0000</lastBuildDate>
	<language>zh-Hans</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.3</generator>
	<item>
		<title>Android gradle build 用R8而不使用Proguard</title>
		<link>https://blog.z6z8.cn/2021/03/22/android-gradle-build-%e7%94%a8r8%e8%80%8c%e4%b8%8d%e4%bd%bf%e7%94%a8proguard/</link>
		
		<dc:creator><![CDATA[holdsky]]></dc:creator>
		<pubDate>Mon, 22 Mar 2021 02:00:16 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[学习笔记]]></category>
		<guid isPermaLink="false">http://blog.z6z8.cn/?p=971</guid>

					<description><![CDATA[com.android.tools.build:gradle:3.4.0 3.4.0以后，默认使用R8编译。  [&#8230;]]]></description>
										<content:encoded><![CDATA[<p><code>com.android.tools.build:gradle:3.4.0</code> 3.4.0以后，默认使用R8编译。</p>
<p>可以在<code>gradle.properties</code>添加属性，指定R8是否启用</p>
<pre><code>android.enableR8=true ；// true 启用R8</code></pre>
<p>有时候上述配置并不一定生效，在编译时有可能还是使用<code>Proguard</code>，这时候可以在App 的<code>build.gradle</code>中配置<code>useProguard false</code>，强制关闭Proguard而启用R8</p>
<pre><code>android {
    buildTypes {
        release {
            minifyEnabled true
            useProguard false  //强制关闭Proguard而启用R8，这时将忽略gradle.properties里关于android.enableR8的设置
            }
        }
}</code></pre>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>adb  遍历Android应用包名并删除</title>
		<link>https://blog.z6z8.cn/2020/11/05/adb-%e9%81%8d%e5%8e%86android%e5%ba%94%e7%94%a8%e5%8c%85%e5%90%8d%e5%b9%b6%e5%88%a0%e9%99%a4/</link>
		
		<dc:creator><![CDATA[holdsky]]></dc:creator>
		<pubDate>Thu, 05 Nov 2020 08:53:31 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[学习笔记]]></category>
		<guid isPermaLink="false">http://blog.z6z8.cn/?p=911</guid>

					<description><![CDATA[adb命令 adb usb ==== 重启 adb的 usb连接 adb shell pm list pack [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>adb命令</p>
<pre><code>adb usb ==== 重启 adb的 usb连接
adb shell pm list packages   ==== 列举所有应用包名
adb shell am monitor  ==== 监控手机上的应用启动
adb shell pm uninstall -k  --user 0 包名  ==== 删除包（屏蔽包）</code></pre>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>移动端监听单页应用的URL变化</title>
		<link>https://blog.z6z8.cn/2020/03/19/%e7%a7%bb%e5%8a%a8%e7%ab%af%e7%9b%91%e5%90%ac%e5%8d%95%e9%a1%b5%e5%ba%94%e7%94%a8%e7%9a%84url%e5%8f%98%e5%8c%96/</link>
		
		<dc:creator><![CDATA[holdsky]]></dc:creator>
		<pubDate>Thu, 19 Mar 2020 01:51:04 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[学习笔记]]></category>
		<guid isPermaLink="false">http://blog.z6z8.cn/?p=840</guid>

					<description><![CDATA[问题 对于Native WebView而言，Andoird/iOS都提供相应的方法/代理监听页面URL的变化。 [&#8230;]]]></description>
										<content:encoded><![CDATA[<h1>问题</h1>
<p>对于Native WebView而言，Andoird/iOS都提供相应的方法/代理监听页面URL的变化。例如，Android可以重写<code>doUpdateVisitedHistory</code>方法监听URL变化，iOS可以实现<code>shouldStartLoadWithRequest</code>、<code>decidePolicyForNavigationAction</code>代理监听URL变化</p>
<pre><code class="language-java">@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
  //此处检测url是否有变化
  return super.shouldOverrideUrlLoading(view, url);
}</code></pre>
<pre><code class="language-objc">//UIWebView
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    //此处检测url是否有变化
    return YES;
}

//WKWebView
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
    //此处检测url是否有变化
    decisionHandler(WKNavigationActionPolicyAllow);
}</code></pre>
<p>上述技术实现对一些前端应用能正常工作。然而，遇到单页应用（SPA）时，以上方法并不会被触发--这里涉及单页应用的实现原理，尤其是基于 <code>hash</code>路由的单页应用，其<code>前进/后退</code>的问题更为突出。</p>
<h1>解决思路</h1>
<p>对于前端应用而言，如果开发者使用固定的框架，那么在框架的路由层面拦截监听应较为容易做到。但是实际情况是开发者使用的前端框架不确定，甚至开发者连前端框架都不用，所以我们在前端框架层面截获路由器变得不那么容易。</p>
<p>经过调研，要监听前端页面的URL变化，大致有两种模式：</p>
<ul>
<li>定时器模式</li>
<li>观察者模式</li>
</ul>
<h2>定时器模式</h2>
<p>定期监测URL是否变化，如100毫秒监测一次，与上次监测值对比来判断URL是否变化。定时器，前端可以使用<code>setInterval</code>来实现</p>
<pre><code class="language-js">var oldUrl = window.location.href;
setInterval(function(){
  if (oldUrl !== window.location.href) {
    //通知Native Url变化
    oldUrl = window.location.href;
  }
},100);</code></pre>
<p>当然，Native也可以开启定时器监测<code>window.location.href</code>。</p>
<p>定时器模式的特点是实现简单，适用范围广；缺点也显而易见，监测结果不是十分准确，性能耗用高。而其性能耗用问题在移动端将会放大，故此我们不采用此模式。</p>
<h2>观察者模式</h2>
<p>上面提到的<code>doUpdateVisitedHistory</code>、<code>shouldStartLoadWithRequest</code>、<code>decidePolicyForNavigationAction</code>的实现可以算作观察者模式。</p>
<p>前面提到，单页应用页面切换在移动端webview的行为表现，并不会每次都通知Native，我们要做的就是通过某种方法来完善这个页面切换的事件通知。</p>
<p>对于观察者模式，iOS中有KVO（key-value-observing）机制，遍历UIWebView和WKWebView的属性发现：</p>
<ul>
<li>WKWebView的<code>URL</code>属性能够响应KVO机制，当前端页面（包括单页应用的页面）URL有变化时，KVO机制可以监测到。</li>
<li>UIWebView的<code>request</code>属性并不能响应KVO机制，不能用它检测URL变化。也就是说，单纯使用UIWebView的能力接口不能完全监测URL变化</li>
</ul>
<p>至此，在Native侧建立观察者的思路并不适用所有情况，我们需要再返回前端侧研究下单页应用的URL变化。</p>
<p>单页应用，通过<code>hash</code>或<code>window.history</code>可以做到改变URL，使得不刷新页面的情况下重新渲染。我们只要监测<code>hash</code>和<code>window.history</code>，当它们发生变化时去检测URL的变化：</p>
<ul>
<li>
<p>通过<code>hash</code>改变URL，会触发<code>hashchange</code>事件。当监听到<code>hashchange</code>事件时，去检测URL的变化。</p>
</li>
<li>
<p><code>window.history</code>相关的事件为<code>popstate</code>。当监听到<code>popstate</code>事件时，去检测URL的变化。</p>
<p><code>History.back()</code>、<code>History.forward()</code>、<code>History.go()</code>会触发<code>popstate</code>事件</p>
</li>
<li>
<p>另外，<code>History.pushState()</code>和<code>History.replaceState()</code>不会触发<code>popstate</code>事件，所以我们要hook这两个方法，以检测URL的变化。</p>
</li>
</ul>
<h1>方案实现</h1>
<p>结合以上，最终我们可以采用的可行方案如下 :</p>
<table>
<thead>
<tr>
<th>Android WebView</th>
<th>iOS UIWebView</th>
<th>iOS WKWebView</th>
</tr>
</thead>
<tbody>
<tr>
<td>前端监测 <code>hash</code>和<code>window.history</code>，通知Native</td>
<td>前端监测 <code>hash</code>和<code>window.history</code>，通知Native</td>
<td>Native监测<code>WKWebView.URL</code></td>
</tr>
</tbody>
</table>
<p><em>注意：上述方案并不是唯一方案，但确实是一个可行方案</em></p>
<h2>WKWebView监测URL部分实现</h2>
<pre><code class="language-objc">//添加观察者
[self addObserver:wkwebview forKeyPath:@"URL" options:NSKeyValueObservingOptionNew context:nil];

//接收观察事件
- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary&lt;NSKeyValueChangeKey,id&gt; *)change context:(void *)context
{
  //url变化，触发相应动作
}

//使用完毕后移除观察者
[self removeObserver:wkwebview forKeyPath:@"URL"];</code></pre>
<h2>前端监测URL部分实现</h2>
<pre><code class="language-js">//监听hash变化
window.addEventListener('hashchange',function(event){
  //通过bridge通知Native URL变化
});

//监听history变化,popstate只能监听History.back(),History.forward()、History.go()
window.addEventListener('popstate',function(event){
  //通过bridge通知Native URL变化
});

//hook History.pushState()  History.replaceState()
var _wr = function(type) {
    var orig = history[type];
    return function() {
        var rv = orig.apply(this, arguments);
        var e = new Event('ffpd'+type);
        e.arguments = arguments;
        window.dispatchEvent(e);
        return rv;
    };
};
history.pushState = _wr('pushState');
history.replaceState = _wr('replaceState');

window.addEventListener('ffpdpushState',function(event){
  //通过bridge通知Native URL变化
});
window.addEventListener('ffpdreplaceState',function(event){
  //通过bridge通知Native URL变化
});</code></pre>
<p>参考：<a href="https://stackoverflow.com/questions/4570093/how-to-get-notified-about-changes-of-the-history-via-history-pushstate">https://stackoverflow.com/questions/4570093/how-to-get-notified-about-changes-of-the-history-via-history-pushstate</a></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>学习笔记：WindowManager显示Android全局悬浮窗口</title>
		<link>https://blog.z6z8.cn/2019/12/18/%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0%ef%bc%9awindowmanager%e6%98%be%e7%a4%baandroid%e5%85%a8%e5%b1%80%e6%82%ac%e6%b5%ae%e7%aa%97%e5%8f%a3/</link>
					<comments>https://blog.z6z8.cn/2019/12/18/%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0%ef%bc%9awindowmanager%e6%98%be%e7%a4%baandroid%e5%85%a8%e5%b1%80%e6%82%ac%e6%b5%ae%e7%aa%97%e5%8f%a3/#respond</comments>
		
		<dc:creator><![CDATA[holdsky]]></dc:creator>
		<pubDate>Wed, 18 Dec 2019 02:26:15 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[学习笔记]]></category>
		<guid isPermaLink="false">http://blog.z6z8.cn/?p=658</guid>

					<description><![CDATA[我用Android手机装了个电商软件，抢购用。自己手机的状态栏不能显示秒级别的时间，只能精确到分钟。为了能准确 [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>我用Android手机装了个电商软件，抢购用。自己手机的状态栏不能显示秒级别的时间，只能精确到分钟。为了能准确的把握抢购时间，自己边学习边开发了一个时间显示悬浮窗。</p>
<h1>WindowManager</h1>
<p><a href="https://blog.csdn.net/robertcpp/article/details/51628643" title="参考文章">参考文章</a><br />
WindowManager可以在其他应用最上层，甚至手机桌面最上层显示窗口。</p>
<ul>
<li>使用Context.getSystemService(Context.WINDOW_SERVICE)来获取WindowManager。</li>
<li>API 17推出了Presentation，它将自动获取display的Context和WindowManager，可以方便地在另一个display上显示窗口</li>
<li>使用WindowManager继承自基类的addView方法和removeView方法来显示和隐藏窗口</li>
<li>WindowManager实现悬浮窗需要声明权限，在manifest中添加如下权限：<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /></li>
<li>在MIUI上需要在设置中打开本应用的”显示悬浮窗”开关，并且重启应用，否则悬浮窗只能显示在本应用界面内，不能显示在手机桌面上。</li>
</ul>
<h1>具体过程</h1>
<h2>创建工程</h2>
<p>用Android Studio创建一个Android Basic Activity工程<br />
<img decoding="async" src="/wp-content/uploads/2019/12/BasicActivity.png" alt="" /></p>
<h2>添加权限</h2>
<p>修改<code>AndroidManifest.xml</code>，添加下面结构的数据</p>
<pre><code class="language-xml">&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;manifest &gt;
&lt;!--    显示顶层浮窗权限  --&gt;
    &lt;uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"&gt;
    &lt;/uses-permission&gt;
&lt;/manifest&gt;</code></pre>
<h2>修改代码</h2>
<p>给MainActivity添加两个属性</p>
<pre><code class="language-java">public class MainActivity extends AppCompatActivity {
    TextView textView; //用于显示时间
    Timer timer;//用于定时刷新时间
    ...
}</code></pre>
<p>Android Basic Activity工程创建后，自带一个按钮，给按钮添加点击事件的处理</p>
<pre><code class="language-java">
final View.OnClickListener listener = new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
                // 类型 TYPE_SYSTEM_OVERLAY ，当悬浮窗口在其他App窗口上面时，不会隔断触摸事件，其他App能正常使用。
                //若要隔断触摸事件，可以使用TYPE_SYSTEM_ALERT
                params.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
                // 设置flag
                int flags = WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
                // | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
                // 如果设置了WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE，弹出的View收不到Back键的事件
               // FLAG_NOT_TOUCH_MODAL不阻塞事件传递到后面的窗口
                // 设置 FLAG_NOT_FOCUSABLE 悬浮窗口较小时，后面的应用图标由不可长按变为可长按

                params.flags = flags;
                // 不设置这个弹出框的透明遮罩显示为黑色
                params.format = PixelFormat.TRANSLUCENT;
                params.width = 300;
                params.height = 50;
                params.gravity = Gravity.TOP;

                TextView top=new TextView(view.getContext());
                //控件字体位置位于左边
                top.setGravity(Gravity.LEFT);
                top.setText("悬浮窗口");

                WindowManager windowManager = (WindowManager)view.getContext().getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
                windowManager.addView(top,params);

                textView = top;
                startTimer();//启动定时器（实现在后面）
            }
        };

FloatingActionButton fab = findViewById(R.id.fab);
//添加点击事件处理
fab.setOnClickListener(listener);</code></pre>
<p>定时器刷新时间</p>
<pre><code class="language-java">public  void  startTimer(){

        timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {

                Date currentTime = new Date();
                SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                final String dateString = formatter.format(currentTime);

                MainActivity.this.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        textView.setText(dateString);
                    }
                });

            }
        },1000,300);
    }</code></pre>
<p>完整代码如下</p>
<pre><code class="language-java">package com.zxs.windonwtimer;

import android.content.Context;
import android.graphics.PixelFormat;
import android.os.Bundle;

import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;

import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;

import android.view.Gravity;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.TextView;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class MainActivity extends AppCompatActivity {

    TextView textView;
    Timer timer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        final View.OnClickListener listener = new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
                // 类型
                params.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
                // WindowManager.LayoutParams.TYPE_SYSTEM_ALERT
                // 设置flag
                int flags = WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
                // | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
                // 如果设置了WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE，弹出的View收不到Back键的事件
                // FLAG_NOT_TOUCH_MODAL不阻塞事件传递到后面的窗口
                // 设置 FLAG_NOT_FOCUSABLE 悬浮窗口较小时，后面的应用图标由不可长按变为可长按
                // 不设置这个flag的话，home页的划屏会有问题
                params.flags = flags;
                // 不设置这个弹出框的透明遮罩显示为黑色
                params.format = PixelFormat.TRANSLUCENT;
                params.width = 300;//WindowManager.LayoutParams.MATCH_PARENT;
                params.height = 50;//WindowManager.LayoutParams.MATCH_PARENT;
                params.gravity = Gravity.TOP;

                TextView top=new TextView(view.getContext());
                //控件字体位置位于左边
                top.setGravity(Gravity.LEFT);
                top.setText("悬浮窗口");

                WindowManager windowManager = (WindowManager)view.getContext().getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
                windowManager.addView(top,params);

                textView = top;
                startTimer();
            }
        };
        FloatingActionButton fab = findViewById(R.id.fab);
        fab.setOnClickListener(listener);
    }

    public  void  startTimer(){

        timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {

                Date currentTime = new Date();
                SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                final String dateString = formatter.format(currentTime);

                MainActivity.this.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        textView.setText(dateString);
                    }
                });

            }
        },1000,300);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}</code></pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.z6z8.cn/2019/12/18/%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0%ef%bc%9awindowmanager%e6%98%be%e7%a4%baandroid%e5%85%a8%e5%b1%80%e6%82%ac%e6%b5%ae%e7%aa%97%e5%8f%a3/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>学习笔记：使用Android  V8 （J2V8）JavaScript引擎</title>
		<link>https://blog.z6z8.cn/2019/11/28/%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0%ef%bc%9a%e4%bd%bf%e7%94%a8android-v8-%ef%bc%88j2v8%ef%bc%89javascript%e5%bc%95%e6%93%8e/</link>
					<comments>https://blog.z6z8.cn/2019/11/28/%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0%ef%bc%9a%e4%bd%bf%e7%94%a8android-v8-%ef%bc%88j2v8%ef%bc%89javascript%e5%bc%95%e6%93%8e/#respond</comments>
		
		<dc:creator><![CDATA[holdsky]]></dc:creator>
		<pubDate>Thu, 28 Nov 2019 09:14:32 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[学习笔记]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[javascrip]]></category>
		<category><![CDATA[v8]]></category>
		<guid isPermaLink="false">http://blog.z6z8.cn/?p=586</guid>

					<description><![CDATA[集成 在Android Studio的Android工程中，需要在build.gradle文件内容里添加依赖指 [&#8230;]]]></description>
										<content:encoded><![CDATA[<h1>集成</h1>
<p>在Android Studio的Android工程中，需要在build.gradle文件内容里添加依赖指令，然后gradle构建就会自动化集成J2V8引擎</p>
<pre><code class="language-gradle">dependencies {
    implementation 'com.eclipsesource.j2v8:j2v8:5.0.103@aar'
}</code></pre>
<p>J2V8的最新版本，可以在marven仓库中查看<br />
<a href="https://mvnrepository.com/artifact/com.eclipsesource.j2v8/j2v8">https://mvnrepository.com/artifact/com.eclipsesource.j2v8/j2v8</a></p>
<h1>使用示例</h1>
<p>示例摘自https://eclipsesource.com/blogs/tutorials/getting-started-with-j2v8/</p>
<pre><code class="language-java">import com.eclipsesource.v8.V8;

public static void main(String[] args) {
 V8 runtime = V8.createV8Runtime();
 int result = runtime.executeIntegerScript(""
  + "var hello = 'hello, ';\n"
  + "var world = 'world!';\n"
  + "hello.concat(world).length;\n");
 System.out.println(result);
 runtime.release();
}</code></pre>
<h1>访问JavaScript对象（Object）</h1>
<p>假设有这样一段JS脚本</p>
<pre><code class="language-javascript">var jsobj = {};
jsobj.hello = "world";</code></pre>
<p>在J2V8中可以直接访问jsobj对象</p>
<pre><code class="language-java">import com.eclipsesource.v8.V8;

public static void main(String[] args) {
  V8 runtime = V8.createV8Runtime();
  runtime.executeVoidScript(""
    + "var jsobj = {};\n"
    + "jsobj.hello = 'world';\n");

// 访问jsobj的属性
  V8Object jsobj = runtime.getObject("jsobj");
  System.out.println(jsobj.getString("hello"));
  jsobj.release();

  runtime.release();
}</code></pre>
<p>需要注意，<code>V8Object</code>需要自己手动释放</p>
<h1>执行JavaScript函数</h1>
<p>JS脚本</p>
<pre><code class="language-javascript">
function test(a,b){
    return a+b;
}

var jsobj = {};
jsobj.func = test;
</code></pre>
<p>Java代码</p>
<pre><code class="language-java">V8 runtime = V8.createV8Runtime();
runtime.executeVoidScript("上面js脚本")

//包装参数
V8Array parameters = new V8Array(1).push(2);
//调用js test方法
runtime.executeIntegerFunction("test",parameters);
//调用jsobj.func
V8Object jsobj = runtime.getObject("jsobj");
jsob.executeIntegerFunction("func",parameters);

//释放
parameters.release();
jsobj.release();
runtime.release();</code></pre>
<h1>JS调用Java方法</h1>
<p>需要注册实现了<code>JavaCallback </code>接口的对象</p>
<pre><code class="language-java">JavaVoidCallback callback = new JavaVoidCallback() {
    @Override
    public void invoke(final V8Object receiver, final V8Array parameters) {
        System.out.println("xxxx");
    }
}

V8 runtime = V8.createV8Runtime();
// 注册到 js 全局函数，函数名为 &lt;code&gt;JavaFunc&lt;/code&gt;
runtime.registerJavaMethod(callback, "JavaFunc");</code></pre>
<p>在js中使用</p>
<pre><code class="language-javascript">JavaFunc(1,2,3);</code></pre>
<h2>JS调用Java对象实例方法</h2>
<p>使用<br />
V8Object.registerJavaMethod(object, javaMedthod, jsMethod, paramlist);</p>
<ul>
<li>object  java对象</li>
<li>javaMedthod  object上的方法名</li>
<li>jsMethod  js环境中的方法名</li>
<li>paramlist  这里指参数类型列表</li>
</ul>
<pre><code class="language-java">V8 runtime = V8.createV8Runtime();

Object test = new test();
V8Object v8test = new V8Object(runtime);
runtime.add("test", v8test);

v8test.registerJavaMethod(test, "nativeFunc", "jsFunc", new Class&lt;?&gt;[] { String.class });</code></pre>
<p>在js中使用</p>
<pre><code class="language-javascript">test.jsFunc('hello, world');</code></pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.z6z8.cn/2019/11/28/%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0%ef%bc%9a%e4%bd%bf%e7%94%a8android-v8-%ef%bc%88j2v8%ef%bc%89javascript%e5%bc%95%e6%93%8e/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
