Android下的skia編譯和使用

概述:

Skia是google的一個跨平臺圖形庫,google自家的android系統、chrome瀏覽器、最新的fuchsia系統以及最新的flutter跨平臺開發框架等,其底層的圖形渲染框架都是基於skia。

步驟

準備環境和工具:

  1. 編譯庫時不推薦用windows,linux會方便很多,筆者採用的是ubantu16.04。

  2. python2.7(這裏不推薦用python3,可能編不過),ubantu上很簡單。

    sudo apt install python2.7

  3. c++ 編譯環境, clang

    sudo apt install clang

  4. git 其實這個不用說了

    sudo apt install git

  5. ninja

    sudo apt install ninja

  6. ndk,安裝方法參見google官方文檔

  7. patchelf,爲什麼要先安裝這個工具,這先賣個關子

  8. 上述工具可能不全,如果在執行後續步驟中還有什麼沒用安裝的,大家自行安裝。

開始編譯:

  1. 首先,拉取代碼

    git clone git clone https://skia.googlesource.com/skia.git

    如果拉取失敗可能是牆的問題,請自行準備好梯子,然後開始設置git的翻牆代理。完了再拉代碼應該就ok了。

  2. 切換你準備選定的分支,筆者這裏選用的最新的chrome66分支

  3. 命令行定位到skia根目錄, 執行下列語句

    python tools/git-sync-deps 生成bin/gn

    tools/install_dependencies.sh 獲取需要的依賴庫頭文件

  4. 執行命令,生成ninja需要的文件。

    bin/gn gen out/arm --args='ndk_api=21 ndk="/home/wangli/Android/Sdk/ndk-bundle" target_cpu="arm" target_os="android" is_official_build=true is_component_build=true is_debug=false

    skia_use_system_expat=false skia_use_system_freetype2=false skia_use_system_libpng=false skia_use_icu=false skia_use_libjpeg_turbo=false skia_use_libwebp=false skia_use_piex=false'

    • out/arm是動態庫生成的位置,這個可以自己指定

    • ndk_api也要結合自己的需要來更改

    • ndk路徑請更改爲自己的ndk路徑

    • target_cpu是自己生成的指令平臺,可以是arm,arm64,armx64,armx86等。

    命令裏很多參數都是可配置的,可以根據自己的需要,更改參數。要查看所有參數列表請執行命令:

    bin/gn args out/Debug --list

  5. 開始編譯:

    sudo ninja -C out/arm

到了這一步,你可以起身去泡一杯茶了。

如不出意外,該命令執行成功後會在out/arm下生成一個libskia.so。如果失敗的話,看看日誌應該還是很好排查錯誤的,一般都是參數問題。

開始寫Android Demo

  1. 打開AndroidStudio(版本建議在2.2以上,支持cmake)新建工程,記得勾選Include C++ support

  2. 將skia目錄下的include文件夾拷貝到Android工程下的main/cpp目錄下

  3. libskia.so放到jni下對應的架構目錄下

  4. 編寫你的cpp文件,調用skia繪製代碼

  5. 編寫cmakelist文件

    安卓系統底層自身也有一個skia包,這個是各個廠商放進去的,供Android底層代碼調用。本來也什麼說的,但是開發過程中發現,寫好的demo在Android 6.0及6.0以上的系統都可以正常運行,然而一到了5.0及以下的系統,就開始各種花式crash。

    Android5.0及以下的系統在加載so庫時是根據庫的SONAME來加載。如果加進來的第三方so庫和系統已經存在的so庫的SONAME相同(注意SONAME和so的文件名不是同一個概念,SONAME是寫進二進制的一個名字),系統在loadLibrary的時候會默認使用系統的so庫, 從而引發潛在的crash。

    接下來開始更改so包的SONAME,前面賣的關子,就是指這裏。patchelf就是用來修改動態庫的SONAME的,如下:

    sudo patchelf --set-soname libskia_eastedu.so libmyskia.so

    查看soname的命令:

    readelf -d libmyskia.so

改完SONAME後,記得把so的文件名也改成和SONAME一樣。然後開始編輯cmakelist文件,我的cmakeList代碼如下。



> cmake_minimum_required(VERSION 3.4.1) 

set(ANDROID_NDK_REVISION 16) 

set(CMAKE_VERBOSE_MAKEFILE on) 

set(ANDROID_STL "gnustl_shared") 

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11 -fexceptions -frtti") 

set(libs "${CMAKE_SOURCE_DIR}/src/main/jniLibs")

include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/include/android)

include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/include/atlastext)

include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/include/c)

include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/include/codec)

include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/include/config)

include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/include/core)

include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/include/effects)

include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/include/encode)

include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/include/gpu)

include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/include/pathops)

include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/include/ports)

include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/include/private)

include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/include/svg)

include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/include/utils)

include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/include/views)

add_library(libskia_eastedu SHARED IMPORTED )

set_target_properties(libskia_eastedu PROPERTIES

    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libskia_eastedu.so")

add_library(eskia

            SHARED

            src/main/cpp/eskia.cpp )

find_library( android-lib

            android)

target_link_libraries(eskia

        libskia_eastedu

        ${android-lib}

    )
  1. 在java文件中加載對應的lib

    static {

     System.loadLibrary("skia_eastedu");
    
     System.loadLibrary("eskia");
    

    }

不出意外的話,app會正常運行並執行你在cpp文件裏寫的繪製代碼。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章