欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
關(guān)于V8 JavaScript Engine的使用方法研究(三)
轉載地址:http://blog.chinaunix.net/space.php?uid=8272118&do=blog&id=2033361

一、寫(xiě)在前面的話(huà)
前幾篇文章中用于驗證目的而編寫(xiě)的代碼都是基于linux平臺和sdl圖形庫的,雖然效果很好很強大(偶在mac的環(huán)境下也做了類(lèi)似的實(shí)驗,確實(shí)不錯),但是這些實(shí)驗畢竟是基于pc環(huán)境的,沒(méi)有在真正的手機arm環(huán)境下面跑跑總覺(jué)得心里沒(méi)有多大的把握。雖然google io大會(huì )上曾經(jīng)說(shuō)過(guò),android2.2瀏覽器使用的webkit內核就是使用了v8引擎來(lái)加速瀏覽器的運行速度,偶在手機上刷了個(gè)2.2的包,測試了一下瀏覽器,也沒(méi)有感覺(jué)到如何如何地快(偶只是隨便按了幾下,可能不足以說(shuō)明問(wèn)題)。

最后,偶還是決定要動(dòng)動(dòng)手,把v8引擎弄到真機上運行一下,中國有句俗話(huà)“是騾子是馬,牽出來(lái)遛遛”。
本文的以下部分會(huì )非??菰?,主要記錄了偶將v8引擎封裝成一個(gè)jni庫的全部過(guò)程,然后通過(guò)java去調用(推崇java的朋友們不要拍偶,說(shuō)實(shí)話(huà),偶一直把java語(yǔ)言本身當成是腳本的一種)。

二、實(shí)驗方法記錄
1、把v8引擎單獨編譯成一個(gè).a或者.so文件
原本希望能夠把v8引擎的源代碼直接編譯到j(luò )ni的源代碼里面,但是后來(lái)發(fā)現既然android從2.0開(kāi)始就有這東西的話(huà),干嘛不拿來(lái)直接用呢?簡(jiǎn)單地搜索了一下android源代碼(偶用的是2.1eclair的源代碼環(huán)境,但是郁悶的是編譯出來(lái)的程序不可以在1.5和1.6的環(huán)境下工作,具體原因偶還需要查一查),發(fā)現在$(ANDROID_SRC_ROOT)/external/webkit/目錄下面,有一個(gè)叫做V8Binding的目錄,這里面就有一個(gè)叫做v8的目錄,該目錄下面就是一個(gè)完整的v8引擎了,從其他的諸如binding以及jni的目錄來(lái)看,android的開(kāi)發(fā)者們也是一直在琢磨著(zhù)把v8庫編譯成一個(gè)so或者一個(gè).a文件,把接口暴露給上層模塊,通過(guò)jni的方式去調用?;氐缴弦患壞夸?,打開(kāi)Android.mk文件,呵呵,原來(lái)如此,編譯腳本進(jìn)行編譯的時(shí)候是需要看到一個(gè)叫做JS_ENGINE的環(huán)境變量的,如果該變量取值為“v8”,則將v8引擎編譯成.a文件,然后鏈接到webkit里面去,如果JS_ENGINE的取值是“jsc”,那么編譯腳本將使用webkit內置的JavaScriptCore中的代碼來(lái)生成腳本引擎。

通過(guò)查看Android.mk文件知道了如何讓編譯環(huán)境生成libv8.a的方法以后,剩下的事情就簡(jiǎn)單多了。
$cd ~/android-src
$export JS_ENGINE=v8
$make
然后,就可以出去散散心了,整個(gè)編譯過(guò)程會(huì )非常地漫長(cháng)(大概有45分鐘左右吧??。?br>
散步歸來(lái),發(fā)現已經(jīng)make好了。那么就要找一找這個(gè)libv8.a或者libv8.so到底放在什么地方了。
最后,偶找到了這個(gè):
$(ANDROID_SRC_ROOT)/out/target/product/generic/obj/STATIC_LIBRARIES/libv8_intermediates/libv8.a
如此說(shuō)明,v8引擎的靜態(tài)庫已經(jīng)成功地生成出來(lái)了!好,下一步,就要想辦法把這個(gè).a文件鏈接到j(luò )ni庫里面去了。

查了一下ndk的文檔,在android-mk.txt文檔中找到了這樣一個(gè)參數:
LOCAL_STATIC_LIBRARIES
    The list of static libraries modules (built with BUILD_STATIC_LIBRARY)
    that should be linked to this module. This only makes sense in
    shared library modules.
看這個(gè)幫助的說(shuō)明,似乎是說(shuō)這里面的staticlibrary是要用BUILD_STATIC_LIBRARY編譯成的才行。偶剛剛已經(jīng)在android的源碼編譯過(guò)程中拿到了libv8.a,那么在這里似乎不能夠直接用這個(gè)參數。于是,偶決定放棄ndk,既然libv8.a是用android的源代碼編譯出來(lái)的,那么就用源代碼中提供的工具鏈來(lái)生成jni吧,android自己的代碼生成的.a靜態(tài)庫,用它自己的工具鏈總可以完成鏈接吧?!

2、用sdk開(kāi)始搭建一個(gè)簡(jiǎn)單的android應用程序框架
jni和java端的調用程序,這兩者正常關(guān)系是先編寫(xiě)java包裝類(lèi),然后利用javah生成jni相關(guān)定義的頭文件。偶在這里也遵循這個(gè)順序來(lái)一步一步地走。無(wú)論是用eclipse還是用android命令行腳本生成一個(gè)項目都可以,既然作實(shí)驗就要做得像真的一樣,偶把測試項目中的普通TextView給換成了SurfaceView(畢竟效率要高一些嘛)。然后,就是編寫(xiě)一個(gè)簡(jiǎn)單的wrapper類(lèi),導出了3個(gè)native的java函數,這三個(gè)函數是需要用jni去實(shí)現的。

偶只把java代碼貼在這里,不做更多說(shuō)明:
public class V8Wrapper {
    private static final String TAG = "V8Wrapper";
    protected SurfaceHolder m_surf_holder ;
    protected byte [] m_js_source ;
    
    V8Wrapper(SurfaceHolder surf_holder)  {
        m_surf_holder = surf_holder ;
        m_js_source = null ;
    }
   
    public String V8GetVersion() {
        return v8_get_version() ;
    }
   
    public boolean V8LoadJS(String js_fname) {
        FileInputStream fis = null ;
        FileChannel fc = null;
        ByteBuffer bb = null ;
        int flen = 0 ;
       
        try {
            fis = new FileInputStream(js_fname) ;
        } catch(FileNotFoundException e) {
            Log.e(TAG, "can't open javascript file : " + js_fname) ;
            return false ;
        }
         
        fc = fis.getChannel() ;
        try {
            flen = (int)(fc.size());
            bb = ByteBuffer.allocate(flen);
            fc.read(bb);
        } catch(IOException e) {
            Log.e(TAG, "ByteBuffer.allocate() or fc.read() failed, fc.size=" + String.valueOf(flen)) ;
            return false ;
        }
       
        bb.flip() ;
       
        m_js_source = null ;
        m_js_source = bb.array() ;

        return true ;
    }

    public boolean V8RunJS() {
        if(m_js_source == null) {
            return false ;
        }
       
        return v8_run_js(m_js_source) ; 
    }
   
    public boolean V8OnTouch(MotionEvent event) {
        if(m_js_source == null) {
            return false ;
        }
         
        return v8_on_touch(m_js_source, (int)(event.getX()), (int)(event.getY())) ; 
    }
   
    private native String  v8_get_version() ;
    private native boolean v8_on_touch(byte [] js_source, int x, int y) ;
    private native boolean v8_run_js(byte [] js_source) ;
   
    static {
        System.loadLibrary("v8wrapper") ;
    }
}
這里的v8_get_version()函數,只是用來(lái)驗證能否從jni函數中調用libva.a的函數用的,以后的實(shí)現中可以忽略,畢竟知道自己調用的v8引擎的版本號也是好的。

3、開(kāi)始編寫(xiě)jni模塊
(1)一些準備工作
$cd $(ANDROID_SRC_ROOT)
$. build/envsetup.sh
$mkdir external/myapps/v8wrapper
$cd external/myapps/v8wrapper
ok,現在可以開(kāi)始要做的事情了,第一件事情自然是編寫(xiě)makefile了,創(chuàng )建Android.mk文件,看上去像下面這樣:
ifneq ($(TARGET_SIMULATOR),true)
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= v8wrapper.cpp
LOCAL_C_INCLUDES += $(JNI_H_INCLUDE) \
    $(LOCAL_PATH)/../../webkit/V8Binding/v8/include \
    $(LOCAL_PATH)/../../skia/include \
    $(LOCAL_PATH)/../../skia/include/core \
    $(LOCAL_PATH)/../../skia/include/images \
    $(LOCAL_PATH)/../../skia/include/graphics \
    $(LOCAL_PATH)/../../skia/include/utils
LOCAL_CFLAGS +=-O0
LOCAL_MODULE := libv8wrapper
LOCAL_SHARED_LIBRARIES := libcutils libskia
LOCAL_STATIC_LIBRARIES := libv8
LOCAL_PRELINK_MODULE := false
include $(BUILD_SHARED_LIBRARY)
endif  # TARGET_SIMULATOR != true

需要提幾句的地方:
(a) LOCAL_PRELINK_MODULE := false
這個(gè)屬性一定要有,因為偶在此做實(shí)驗的jni是不再“正?!钡腶ndroid系統中的,android系統源代碼在編譯的過(guò)程中會(huì )自動(dòng)忽略此jni。為了告訴android的編譯系統此模塊不在原先正常的系統中,但是也要編譯出來(lái),所以只好把這里寫(xiě)上這么一個(gè)屬性了。

(b)LOCAL_SHARED_LIBRARIES := libcutils libskia
鏈接libcutils.so的目的在于偶要使用android系統的log函數,而鏈接libskia.so的目的在于,整個(gè)android系統的ui框架,其基礎都是建立在skia這個(gè)圖形庫的前提之下的,android的framework在繪制ui的過(guò)程中大量使用了jni模塊去調用skia庫的功能,既然偶自己可以通過(guò)c\c++代碼直接調用skia庫,那我干嘛還要java層去做這樣的事情呢?腳本引擎的效率肯定要比二進(jìn)制代碼低,因此,偶在jni里面選擇了盡量不去麻煩android框架去做一些在jni里面就能夠做到的事情(例如,屏幕繪圖,圖片解碼、貼圖等操作,本著(zhù)能省則省的原則來(lái)避免不必要的性能浪費)。

在這里插一嘴,在android框架代碼的Canvas.h文件中($(ANDROID_SRC_ROOT)/frameworks/base/graphics/java/android/graphics/Canvas.h),可以看到如下的定義:
final int mNativeCanvas;
經(jīng)過(guò)進(jìn)一步的代碼追蹤,偶發(fā)現這個(gè)所謂的mNativeCanvas實(shí)際上就是指向skia庫中的一個(gè)SkCanvas對象的指針。(java里面沒(méi)有指針數據類(lèi)型,為了保留這個(gè)指針,android框架的設計者不得已在這里使用了int數據類(lèi)型在java環(huán)境中保存c/c++環(huán)境的指針,偶不是第一個(gè)發(fā)現這個(gè)小秘密的,已經(jīng)有臺灣的高人發(fā)現過(guò)了,在此偶只是強調一下)既然知道了這一點(diǎn),偶在jni的實(shí)現中,得到j(luò )ava環(huán)境的Canvas對象以后,只需要把Canvas對象的mNativeCanvas屬性中的數據進(jìn)行強制類(lèi)型轉換就可以很方便地得到android系統中指向SkCanvas對象的指針,剩下的所有屏幕操作都可以籍由這個(gè)指針,結合skia庫來(lái)完成,何勞dalvik大駕?!呵呵,根據偶最后在真機上的運行結果來(lái)看,上面的一點(diǎn)點(diǎn)小hack確實(shí)對jni中提升屏幕繪制效率有很大幫助。(上面這一段文字很不好寫(xiě),更不好懂,感興趣的朋友可以多讀幾遍)

在jni里與此相關(guān)的函數如下:
static SkCanvas * get_skcanvas(JNIEnv * env, const jobject & canvas_obj) {
  const char * tag = "jni:get_skcanvas, " ;
  jclass cls_canvas ;
  jfieldID fid_native_canvas ;

  cls_canvas = env->GetObjectClass(canvas_obj) ;
  // 大家注意了,這一句就是獲取mNativeCanvas屬性的存儲位置id
  fid_native_canvas = env->GetFieldID(cls_canvas, "mNativeCanvas", "I") ;
  if(fid_native_canvas == NULL) {
    log(tag, "lookup mNativeCanvas in Canvas class failed!") ;
    return (SkCanvas *)(NULL) ;
  }
  // 這一句就通過(guò)GetIntFiled函數把里面的數據取出來(lái),然后強制類(lèi)型轉換即可
  return (SkCanvas *)(env->GetIntField(canvas_obj, fid_native_canvas)) ;
}
其他的語(yǔ)法都是jni的常規語(yǔ)法,在此偶就不再聒噪了。

(c)LOCAL_STATIC_LIBRARIES := libv8
這個(gè)就不用偶多說(shuō)了,libv8.a既然生成出來(lái)了,就不要浪費,自然需要鏈接進(jìn)來(lái)。(誰(shuí)知盤(pán)中庫,庫庫皆辛苦。。。)

(d) $(LOCAL_PATH)/../../webkit/V8Binding/v8/include \
此include路徑是v8引擎在android 2.1源代碼中的位置,此時(shí),v8引擎是作為webkit的一部分存在的;而在android 2.2源代碼以后,v8引擎的位置將獨立于webkit,自成一體,這時(shí)候的include路徑應該改為:
$(LOCAL_PATH)/../../v8/include \
也就是說(shuō)android 2.2源代碼編譯環(huán)境把v8目錄從webkit目錄內拿出來(lái)了。

(2)編寫(xiě)jni模塊
編寫(xiě)過(guò)程是一個(gè)非常讓人郁悶的過(guò)程(尤其是偶采用的是android源代碼工具鏈進(jìn)行編譯,而ndk-r4中自帶的調試功能不可以使用,但是畢竟android源代碼作為編譯環(huán)境可以調用很多android內部的library,這一點(diǎn)是要比ndk爽很多地。。。)。

在這里需要說(shuō)明一下SurfaceView中進(jìn)行屏幕繪制的關(guān)鍵代碼(java版本的):
try {
    m_canvas = m_surf_holder.lockCanvas(null) ;
        m_canvas.drawBitmap(bmp, x, y, null) ;
} finally {
    if (m_canvas != null) {
              m_surf_holder.unlockCanvasAndPost(m_canvas);
         }
}
在java代碼中,使用SurfaceView進(jìn)行繪圖的時(shí)候分為三步:
(a)m_canvas = m_surf_holder.lockCanvas(null) ;
首先是通過(guò)一個(gè)SurfaceHolder的對象調用lockCanvas()函數,該函數會(huì )返回一個(gè)Canvas對象(就是這里的m_canvas,至于SurfaceHolder對象的獲取,可以通過(guò)調用getHolder()取得)。

(b)m_canvas.drawBitmap(bmp, x, y, null) ;
這里就是使用m_canvas進(jìn)行繪圖,貼圖操作,在這些繪圖操作進(jìn)行的過(guò)程中,所有操作都繪制到了一個(gè)內存中的屏幕上,并不會(huì )立即顯示到當前的屏幕上。

(c)m_surf_holder.unlockCanvasAndPost(m_canvas);
只有調用了unlockCanvaAndPost()函數以后,剛剛繪制在m_canvas上的所有內容才會(huì )顯示在當前屏幕上。

在偶的jni模塊實(shí)現中,把上述在java中的三個(gè)步驟統統地搬到了jni函數中,用c++去完成。雖然看上去麻煩一些,畢竟省得麻煩dalvik去進(jìn)行幾次jni到j(luò )ava以及java到j(luò )ni的反射過(guò)程,會(huì )提升一些執行效率(呵呵,當然了,也可能是偶的心里作用吧,通過(guò)這么做可以讓偶心里安慰一些??。?。

(3)關(guān)于v8引擎的回調
基本的腳本執行,以及函數回調原理在偶的上兩篇文章中已經(jīng)講述過(guò)了,在此不再聒噪。只是偶在不知道v8的名字空間會(huì )引起jni的任何問(wèn)題之前,還是沒(méi)有敢直接使用:
using namespace v8 ;
這樣的語(yǔ)句。所以很多在前兩篇文章中很簡(jiǎn)單的聲明,就要寫(xiě)的很繁瑣了(重復地敲這些無(wú)用的東西,偶的手指都有些酸了)例如:以前的Handle<String>,現在就要寫(xiě)成v8::Handle<v8::String>。
在此真機測試中,偶為javascript腳本導出了如下函數:
(a)set_back_color(r, g, b):設置背景顏色,RGB格式。
(b)set_draw_color(r, g, b):設置畫(huà)筆顏色,RGB格式。
(c)set_txt_size(size):設置顯示文字的大小,支持小數點(diǎn),必須大于0。
(d)draw_line(x0, y0, x1, y1):使用畫(huà)筆顏色畫(huà)直線(xiàn)。
(e)clear():用背景色填充整個(gè)屏幕,顧名思義就是清屏。
(f)draw_img(x, y, fname):以(x,y)為左上角坐標貼圖,fname為圖片名稱(chēng)(圖片一定要放在v8data目錄,圖片格式支持bmp, png, jpeg, gif)
(g)draw_txt(x, y, txt):使用前請設置畫(huà)筆顏色和文字大小,在(x, y)為左上角坐標在屏幕上繪制文字。

最后,腳本支持一個(gè)OnClick(x, y)的回調函數,當屏幕被點(diǎn)按的時(shí)候,v8會(huì )自動(dòng)回調此函數。

所有這些函數在c++的實(shí)現中,多虧了SkCanvas提供的強大功能,偶只用了幾行代碼就解決了戰斗,skia確實(shí)名不虛傳(再次贊揚一下skia的原創(chuàng )人員)。

感興趣的朋友可以通過(guò)改寫(xiě)偶在v8data目錄下面提供的t1.js腳本文件來(lái)看看不同的運行結果。

(4)編譯方法
$ cd $(ANDROID_SCR_ROOT)/external/myapps/v8wrapper
$mm
注意,一定要在$(ANDROID_SCR_ROOT)目錄下運行過(guò)“.build/envsetup.sh”腳本后才能夠用mm進(jìn)行編譯(這腳本方便,mm命令可以理解為——》“美眉”,讓美眉幫偶編譯,呵呵,不過(guò)這位美眉的脾氣不太好,編譯腳本稍微寫(xiě)的不對就不給編譯。感慨一下,如果美眉能夠自動(dòng)理解這些,偶該多么地幸福啊!~(#@*&$(@#*&$)

編譯完成以后,需要手工把如下路徑下的文件拷貝到j(luò )ava項目的lib/armeabi目錄下:
$(ANDROID_SRC_out/target/product/generic/system/lib/libv8wrapper.so
畢竟沒(méi)有了ndk-build腳本的幫忙,什么事情都要自己動(dòng)手。

(5)運行方法
無(wú)論大家用ant或者eclipse都可以生成安裝包(大概515k左右,懶得編譯的朋友,可以下載偶提供的apk包)。
(a)直接adb install v8test-debug.apk安裝到手機上(模擬器上安裝必須是2.0或者更高版本的才行)
(b)通過(guò)adb shell在/sdcard下面建立一個(gè)目錄叫做v8data(注意,全部小寫(xiě)的v8data目錄)
(c)把java代碼中的V8Test/v8data目錄下的所有文件通過(guò)ddms拷貝到手機sdcard上面的v8data目錄里面
(包括若干張png圖片,以及一個(gè)t1.js腳本)
(d)打開(kāi)“V8TestActivity”程序,如果看到黑黑的屏幕,代表一切正常,否則代表有問(wèn)題。
(e)按下手機的“menu”按鍵,選擇“l(fā)oad”,然后選擇“run”
(f)在屏幕上單擊圖標,會(huì )看到有一個(gè)白色框框跟隨走動(dòng)。

所有這些界面和效果都是用javascript編寫(xiě)的,可以通過(guò)打開(kāi)t1.js文件進(jìn)行修改,然后覆蓋到sdcard上的v8data目錄下即可。連程序都不需要退出,只要重新點(diǎn)按一下"load"和"run"即可看到修改后的結果。

是不是很神奇?!通過(guò)script+c/c++模塊的開(kāi)發(fā)方式可以極大地增加手機應用的靈活性(手機程序最困難的不是開(kāi)發(fā),而是什么都做好了,如何安裝到用戶(hù)的手機里面去?!以及費盡千辛萬(wàn)苦安裝到用戶(hù)手機上了,如何升級?!一次升級哪怕只是ui改變一點(diǎn)點(diǎn),也可能流失用戶(hù)),偶希望通過(guò)這三篇文章加上這些測試代碼,能夠起到拋磚引玉的作用(當然文章中的不足之處引來(lái)各位高手的更多的板磚也是十分歡迎的),能夠對大家有些許用處。

三、實(shí)驗結果展示
到了本文的最后,自然又進(jìn)入了“有圖有真相”時(shí)間,偶也可以給大家展示一下實(shí)驗結果。
1、在2.0模擬器上面的運行效果

2、在偶的nexus one上面的運行效果

3、java調用v8wrapper的源代碼
文件: V8Test.tar.gz
大小: 547KB
下載: 下載

4、v8wrapper的源代碼
文件: v8wrapper.tar.gz
大小: 3KB
下載: 下載

5、完成后的apk安裝包
注意:v8data目錄下面的數據需要下載上面的"3、java調用v8wrapper的源代碼"才能得到。
文件: v8test-signed.tar.gz
大小: 498KB
下載: 下載

最后,通過(guò)偶的實(shí)驗,證明v8引擎————是馬。




本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
android中的surface
Android?圖形系統剖析?(轉)
android c 通過(guò)skia圖形庫繪制文字
【轉】Android手機視頻監控JNI問(wèn)題
Android原理揭秘系列之framework本地方法注冊
jni的異常處理
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久