概述:
Skia是google的一個跨平臺圖形庫,google自家的android系統、chrome瀏覽器、最新的fuchsia系統以及最新的flutter跨平臺開發框架等,其底層的圖形渲染框架都是基於skia。
步驟
準備環境和工具:
編譯庫時不推薦用windows,linux會方便很多,筆者採用的是ubantu16.04。
-
python2.7(這裏不推薦用python3,可能編不過),ubantu上很簡單。
sudo apt install python2.7
-
c++ 編譯環境, clang
sudo apt install clang
-
git 其實這個不用說了
sudo apt install git
-
ninja
sudo apt install ninja
ndk,安裝方法參見google官方文檔
patchelf,爲什麼要先安裝這個工具,這先賣個關子
上述工具可能不全,如果在執行後續步驟中還有什麼沒用安裝的,大家自行安裝。
開始編譯:
-
首先,拉取代碼
git clone git clone https://skia.googlesource.com/skia.git
如果拉取失敗可能是牆的問題,請自行準備好梯子,然後開始設置git的翻牆代理。完了再拉代碼應該就ok了。
切換你準備選定的分支,筆者這裏選用的最新的chrome66分支
-
命令行定位到skia根目錄, 執行下列語句
python tools/git-sync-deps 生成bin/gn
tools/install_dependencies.sh 獲取需要的依賴庫頭文件
-
執行命令,生成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
-
開始編譯:
sudo ninja -C out/arm
到了這一步,你可以起身去泡一杯茶了。
如不出意外,該命令執行成功後會在out/arm下生成一個libskia.so。如果失敗的話,看看日誌應該還是很好排查錯誤的,一般都是參數問題。
開始寫Android Demo
打開AndroidStudio(版本建議在2.2以上,支持cmake)新建工程,記得勾選Include C++ support
將skia目錄下的include文件夾拷貝到Android工程下的main/cpp目錄下
libskia.so放到jni下對應的架構目錄下
編寫你的cpp文件,調用skia繪製代碼
-
編寫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}
)
-
在java文件中加載對應的lib
static {
System.loadLibrary("skia_eastedu"); System.loadLibrary("eskia");
}
不出意外的話,app會正常運行並執行你在cpp文件裏寫的繪製代碼。