Android编译Skia库
本文档提供两种方法编译Skia库
- 使用aosp源码进行编译
- 使用skia源码进行编译
两种编译方法都可以编译,并且都可以使用在多个平台中,且可以使用在不同Android版本中
使用aosp源码编译
第一步是拿到aosp的源码.因为写这篇教程,使用的是msm8996的源码,因此,我就直接使用了.
注意:如果是app开发人员,可能无法拿到跟我一样的源码,则可以使用aosp源码.下面是aosp源码下载教程:
https://source.android.com/docs/setup/download/downloading
大部分情况下,可能无法下载,此时可以使用清华镜像站:https://mirrors.tuna.tsinghua.edu.cn/help/AOSP/
拿到aosp之后,切换到一个比较熟悉的版本中,可以切换到跟我一样的Android 奥利奥版本
第二步进入项目根目录,运行:
. build/envsetup.sh
lunch xxx-debug
mmma external/skia
第三步拷贝out/target/product/xxx/system/lib/libskia.so 和 out/target/product/xxx/system/lib64/libskia.so到app中.
第四步修改对应的错误.
- 运行在Android 7.1 应该没啥问题
- 运行在Android 7.1 以上,会出现xxx.so库未找到的问题.出现这种问题,是因为libskia.so中会加载部分系统内部的so库.现提供两种修改办法
第一种 如果属于定制rom,则可以修改rom的情况下,可以将需要暴露的so库,放入public.libraries.txt文件中
第二种 如果无法修改rom,那么只能将对应的so静态编译进libskia.so中.具体方法如下:
1. 打开external/skia/Android.bp,找到shared_libs和static_libs.将shared_libs中的文件,一个一个添加到static_libs中
2. 举个例子如下:将libdng_sdk移动到static_libs中,然后,重新运行mmma external/skia
3. 部分动态库,无法移植到static_libs的解决办法:
a. 如libicui18n放入到static_libs之后,编译会出错,大概错误如下:error: external/skia/Android.bp:3:1: dependency "libicui18n" of "libskia" missing variant:
b. 上面错误的原因是,libicui18n并没有静态库
c. 接下来就是,编译libicui18n的静态库
d. 对应步骤如下
e. 找到libicui18n的编译文件配置文件.使用find . -name "*.mk" -exec grep -rinH --color=auto "LOCAL_MODULE.*libicui18n" {} \;
f. 本机结果如下:
./out/soong/Android-mini_emulator_x86_64.mk:79473:LOCAL_MODULE := libicui18n
./out/soong/Android-mini_emulator_x86_64.mk:79488:LOCAL_MODULE_STEM := libicui18n
./out/soong/Android-mini_emulator_x86_64.mk:79493:LOCAL_MODULE := libicui18n
./out/soong/Android-mini_emulator_x86_64.mk:79508:LOCAL_MODULE_STEM := libicui18n
./out/soong/Android-mini_emulator_x86_64.mk:79513:LOCAL_MODULE := libicui18n
./out/soong/Android-mini_emulator_x86_64.mk:79528:LOCAL_MODULE_STEM := libicui18n-host
./out/soong/Android-mini_emulator_x86_64.mk:79533:LOCAL_MODULE := libicui18n
./out/soong/Android-mini_emulator_x86_64.mk:79548:LOCAL_MODULE_STEM := libicui18n-host
./out/soong/Android-FindPiano.mk:79034:LOCAL_MODULE := libicui18n
./out/soong/Android-FindPiano.mk:79049:LOCAL_MODULE_STEM := libicui18n
./out/soong/Android-FindPiano.mk:79054:LOCAL_MODULE := libicui18n
./out/soong/Android-FindPiano.mk:79069:LOCAL_MODULE_STEM := libicui18n
./out/soong/Android-FindPiano.mk:79074:LOCAL_MODULE := libicui18n
./out/soong/Android-FindPiano.mk:79089:LOCAL_MODULE_STEM := libicui18n-host
./out/soong/Android-FindPiano.mk:79094:LOCAL_MODULE := libicui18n
./out/soong/Android-FindPiano.mk:79109:LOCAL_MODULE_STEM := libicui18n-host
g. 打开./out/soong/Android-FindPiano.mk并定位到79034行.可以看到libicui18n的位置为:external/icu/icu4c/source/i18n
h. 打开对应的编译配置文件,Android.bp或者Android.mk
i. 添加对应的静态库编译配置,如下
diff --git a/external/icu/icu4c/source/i18n/Android.bp b/external/icu/icu4c/source/i18n/Android.bp
index ef84d97..4c46b16 100644
--- a/external/icu/icu4c/source/i18n/Android.bp
+++ b/external/icu/icu4c/source/i18n/Android.bp
@@ -251,3 +251,16 @@ cc_library_shared {
"-lpthread",
],
}
+
+cc_library_static {
+ name: "libicui18n_s",
+ vendor_available: true,
+ defaults: ["libicui18n_defaults"],
+ host_supported: true,
+ unique_host_soname: true,
+ shared_libs: ["libicuuc"],
+ host_ldlibs: [
+ "-lm",
+ "-lpthread",
+ ],
+}
j. 注意,上面已经将静态库的名字改变,将libicui18n改成了libicui18n_s.因此在libskia的静态库中,应该写成libicui18n_s而不是libicui18n
k. 经过一些列修改之后,skia的编译配置文件,变成如下
shared_libs: [
"libEGL",
"libGLESv2",
- "libdng_sdk",
- "libexpat",
- "libft2",
- "libheif",
- "libicui18n",
- "libicuuc",
- "libjpeg",
- "liblog",
- "libpiex",
- "libpng",
"libvulkan",
- "libz",
- "libcutils",
- "libnativewindow",
+ "libnativewindow",
],
static_libs: [
"libarect",
"libsfntly",
"libwebp-decode",
"libwebp-encode",
+ "libdng_sdk",
+ "libjpeg",
+ "libpng",
+ "libcutils",
+ "libexpat",
+ "libz",
+ "liblog",
+ "libft2_s",
+ "libpiex_s",
+ "libbinary_parse",
+ "libimage_type_recognition",
+ "libtiff_directory",
+ "libicui18n_s",
+ "libicuuc_s",
+ "libicuuc_stubdata",
],
qti_whole_static_libs: [
"libqc-skia",
],
}
l. 从上面的文件可以看到,增加一些以前不存在的库,如libbinary_parse这是因为在编译libpiex时会用到,读者可以在piex的编译配置文件中,找到libbinary_parse的依赖关系
m. 上述文件中的shared_libs中依然有四个库,并没有编译成静态库,是因为,留下来的四个库:libEGL,libGLESv2,libvulkan,libz属于标准ndk,可以直接加载,而不会出现,诸如:libandroid_runtime.so not found的错误
n. 使用mmma external/skia再次编译,得到libskia.so.放入APP中,成功运行.
使用skia源码进行编译
第一步, 进入官网下载源码.源码位置
https://github.com/google/skia
第二步,切换到你想要编译的分支上,比如,这次我目标安卓版本是Android 8.1所以我切到了android/o-release分支
第三步,下载NDK,NDK有不同的版本,因此,要下载对应的版本,怎么查找对应的NDK版本呢? 根据时间.Android 8.1 释放的时间在2017年12月左右,因此NDK版本,差不多也在这个附近.
翻看NDK如下:
可以看到NDK版本应该是r16b.如果不行再试试上下版本的NDK
第四步,开始编译
1. 第一步产生编译文件:bin/gn out/arm64 --args='ndk="ndk路径" target_cpu="arm64"'
2. 在--args中还可以使用的参数有:is_debug表示是否是debug编译 is_component_build表示生成静态库还是动态库.
3. 开始编译 sudo ninja -C out/arm64 -j 8 -v
4. 下面给出本机的运行命令
skia$ bin/gn gen out/arm64 --args='ndk="/media/wanbiao/disk1t/root/SDK/android-ndk-r18b" target_cpu="arm64" is_component_build=true is_debug=false'
skia$ sudo ninja -C out/arm64 -j 8 -v
5. 如果出现部分头文件缺失,则运行tools/install_dependencies.sh 安装相对应的依赖
6. 如要生成32位的库,则将上面命令中的64取掉即可
7. 如果出现编译不通过,大概率是因为NDK的版本不对,我在本机测试过从13到24这几个版本的NDK,都无法正确的编译,只有r16b可以正确编译.
8. 如果将对应的库,放入Android studio的工程之中,进行编译,报出了诸如:__end,__start之类的错误,是因为libskia.so使用的是r16b,而Android studio的工程使用的更高版本的NDK,解决办法就是:在编译libskia.so时,手动指定ld程序.例子如下:
skia$ bin/gn gen out/arm64 --args='ndk="/media/wanbiao/disk1t/root/SDK/android-ndk-r16b" target_cpu="arm64" is_component_build=true is_debug=false extra_ldflags=["-fuse-ld=gold"]'
可以看见,在最后,加入了extra_ldflags参数.
9. 再次重新编译,生成相应的动/静态库
第五步,因为本笔记,写于skia编译之后很久,部分错误处理,可能会忘记,因此,我将本次编译的关于skia的源码,一并上传.
发现CSDN无法上传大于1000MB的文件,因此将其传入百度网盘.
链接: https://pan.baidu.com/s/1ISZ62Pead577zWNbPWcSyg 提取码: 8888 复制这段内容后打开百度网盘手机App,操作更方便哦