Flutter启动流程(Skia引擎)介绍与使用
要想了解 Flutter,你必须先了解它的底层图像渲染引擎 Skia。因为,Flutter 只关心如何向 GPU 提供视图数据,而 Skia 就是它向 GPU 提供视图数据的好帮手。
Skia是一个用C++开发的开源的2D渲染引擎,支持多个硬件和软件平台。而且他是Google chrome, android, Flutter产品里面用到的图形引擎。
Skia简单应用
1、Java外壳
1. public class SkiaView extends View { 2. 3. /** TAG标识 */ 4. private static final String TAG = "SkiaView"; 5. 6. /** 载入动态库 */ 7. static { 8. • try { 9. • System.loadLibrary("SkiaJni"); 10. • } catch(UnsatisfiedLinkError e) { 11. • Log.e(TAG, "Couldn't load native libs"); 12. • e.printStackTrace(); 13. • } 14. } 15. 16. public SkiaView(Context context) { 17. • super(context); 18. } 19. 20. @Override 21. protected void onDraw(Canvas canvas) { 22. • super.onDraw(canvas); 23. • Log.i(TAG, "==draw start=="); 24. • // 调用本地方法 25. • native_renderCanvas(canvas); 26. • Log.i(TAG, "==draw end=="); 27. } 28. 29. /** 本地渲染画布方法 */ 30. private native void native_renderCanvas(Canvas canvas); 31. 32. } 复制代码
2、C/C++封装
2.1我的环境
XP+Eclipse+Cygwin。准备源码。
2.2建立工程
工程地址:AndroidSkia工程根目录jni文件夹。
Build command:bash --login -c "cd WORKSPACE/AndroidSkia && NDKROOT/ndk-build"
$WORKSPACE、$NDKROOT为工作空间、NDK路径。在Cygwin根目录\home[your name]\ .bash_profile文件内配置。 复制代码
3.includes jni、skia等需要的头文件。当前如下:
2.3Android.mk
1. LOCAL_PATH := $(call my-dir) 2. include $(CLEAR_VARS) 3. 4. MY_ANDROID_SOURCE = F:/01.软件/01.开发/05.android/android_sys_src/2.3.3_r1 5. MY_ANDROID_SYSLIB = $(MY_ANDROID_SOURCE)/out/target/product/generic/system/lib 6. #也可以在cygwin\home\Join.bash_profile文件内配置,如下: 7. # export MY_ANDROID_SOURCE="/cygdrive/f/..." 8. # export MY_ANDROID_SYSLIB="/cygdrive/f/..." 9. 10. LOCAL_MODULE := libSkiaJni 11. LOCAL_SRC_FILES := \ 12. jniLoad.cpp \ 13. org_join_skia_SkiaView.cpp 14. 15. LOCAL_C_INCLUDES := \ 16. $(MY_ANDROID_SOURCE)/dalvik/libnativehelper/include/nativehelper \ 17. $(MY_ANDROID_SOURCE)/frameworks/base/include \ 18. $(MY_ANDROID_SOURCE)/system/core/include \ 19. $(MY_ANDROID_SOURCE)/frameworks/base/native/include \ 20. $(MY_ANDROID_SOURCE)/frameworks/base/core/jni/android/graphics \ 21. $(MY_ANDROID_SOURCE)/external/skia/include/core \ 22. $(MY_ANDROID_SOURCE)/external/skia/include/config \ 23. $(MY_ANDROID_SOURCE)/external/skia/include/p_w_picpaths 24. #同时在工程Properties->C/C++ General->Paths and Symbols属性内include相应文件目录 25. #否则编程时找不到.h文件,不便写代码,但不会影响编译。而LOCAL_LDLIBS/LOCAL_LDFLAGS必需添加。 26. 27. #LOCAL_LDLIBS := -L$(MY_ANDROID_SYSLIB) -llog -ljnigraphics -lskia -landroid_runtime 28. #也可以用以下方式指定so库 29. LOCAL_LDFLAGS := \ 30. $(MY_ANDROID_SYSLIB)/liblog.so \ 31. $(MY_ANDROID_SYSLIB)/libjnigraphics.so \ 32. $(MY_ANDROID_SYSLIB)/libskia.so \ 33. $(MY_ANDROID_SYSLIB)/libskiagl.so \ 34. $(MY_ANDROID_SYSLIB)/libandroid_runtime.so 35. 36. include $(BUILD_SHARED_LIBRARY) 复制代码
LOCAL_C_INCLUDES的头文件路径,第一个是jni的,最后三是lskia的,倒数四是ljnigraphics的,其他为基础的(如llog,除了某一是landroid_runtime的,忘了哪个==)。
MY_ANDROID_SYSLIB也可从模拟器导出。
2.4org_join_skia_SkiaView.cpp
1. #include "jniLoad.h" 2. 3. #include <GraphicsJNI.h> 4. #include <SkCanvas.h> 5. #include <SkPaint.h> 6. #include <SkRect.h> 7. #include <SkColor.h> 8. #include <SkTypes.h> 9. #include <SkGraphics.h> 10. 11. static void drawFlag(SkCanvas* canv); 12. 13. static void native_renderCanvas(JNIEnv* env, jobject obj, jobject canvas) { 14. MY_LOGI("==c method start=="); 15. 16. SkCanvas* canv = GraphicsJNI::getNativeCanvas(env, canvas); 17. if (!canv) { 18. • MY_LOGE("==canv is NULL=="); 19. • return; 20. } 21. 22. canv->save(); 23. canv->translate(100, 100); 24. drawFlag(canv); 25. canv->restore(); 26. 27. MY_LOGI("==c method end=="); 28. } 29. 30. /** 画旗帜 */ 31. static void drawFlag(SkCanvas* canv) { 32. SkPaint* paint = new SkPaint(); 33. paint->setFlags(paint->kAntiAlias_Flag); 34. 35. SkRect* rect = new SkRect(); 36. rect->set(0, 0, 200, 100); 37. paint->setColor(SK_ColorRED); 38. canv->drawRect(*rect, *paint); 39. 40. paint->setColor(SK_ColorGRAY); 41. paint->setStrokeWidth(10); 42. canv->drawLine(5, 100, 5, 300, *paint); 43. 44. paint->setTextSize(30); 45. paint->setColor(SK_ColorBLUE); 46. paint->setTextAlign(paint->kCenter_Align); 47. const char* text = "Hello World"; 48. canv->drawText(text, strlen(text), 100, 60, *paint); 49. } 50. 51. /** 52. * JNI registration. 53. */ 54. static JNINativeMethod methods[] = { { "native_renderCanvas", 55. • "(Landroid/graphics/Canvas;)V", (void*) native_renderCanvas } }; 56. 57. int register_org_join_skia_SkiaView(JNIEnv *env) { 58. return jniRegisterNativeMethods(env, "org/join/skia/SkiaView", methods, 59. • sizeof(methods) / sizeof(methods[0])); 60. } 复制代码
2.5jniLoad.h
1. #ifndef JNILOAD_H_ 2. #define JNILOAD_H_ 3. 4. #include <jni.h> 5. #include <utils/Log.h> 6. 7. #define MY_LOG_TAG "JNI_LOG" 8. #define MY_LOGI(...) __android_log_print(ANDROID_LOG_INFO, MY_LOG_TAG, __VA_ARGS__) 9. #define MY_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, MY_LOG_TAG, __VA_ARGS__) 10. 11. #ifdef __cplusplus 12. extern "C" { 13. #endif 14. 15. int jniRegisterNativeMethods(JNIEnv* env, const char* className, 16. • const JNINativeMethod* gMethods, int numMethods); 17. 18. #ifdef __cplusplus 19. } 20. #endif 21. 22. #endif /* JNILOAD_H_ */ 复制代码
2.6jniLoad.cpp
1. #include "jniLoad.h" 2. 3. #include <stdlib.h> 4. 5. int register_org_join_skia_SkiaView(JNIEnv *env); 6. 7. int jniRegisterNativeMethods(JNIEnv* env, const char* className, 8. • const JNINativeMethod* gMethods, int numMethods) { 9. 10. jclass clazz; 11. MY_LOGI("Registering %s natives\n", className); 12. clazz = env->FindClass(className); 13. 14. if (clazz == NULL) { 15. • MY_LOGE("Native registration unable to find class '%s'\n", className); 16. • return JNI_ERR; 17. } 18. if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) { 19. • MY_LOGE("RegisterNatives failed for '%s'\n", className); 20. • return JNI_ERR; 21. } 22. return JNI_OK; 23. } 24. 25. jint JNI_OnLoad(JavaVM* vm, void* reserved) { 26. JNIEnv* env = NULL; 27. jint result = JNI_ERR; 28. 29. if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { 30. • MY_LOGE("GetEnv failed!"); 31. • return result; 32. } 33. 34. MY_LOGI("loading . . ."); 35. 36. if(register_org_join_skia_SkiaView(env) != JNI_OK) { 37. • MY_LOGE("can't load org_join_skia_SkiaView"); 38. • goto end; 39. } 40. /** 41. * register others 42. */ 43. 44. MY_LOGI("loaded"); 45. 46. result = JNI_VERSION_1_4; 47. end: 48. return result; 49. } 复制代码
3、运行效果
Cygwin问题
使用Cygwin时可能遇到的问题,之前都没提到过,现在补上==。
1、make 3.81 bug - error: multiple target patterns. Stop.
[http://cygwin.com/ml/cygwin/2009-04/msg00007.html](https://cygwin.com/ml/cygwin/2009-04/msg00007.html) •下载http://www.cmake.org/files/cygwin/make.exe替换原来的make.exe 复制代码
2、添加当前工程下的头文件和库文件
添加include路径:project->properties->c/c++ build->settings->cygwin c compiler->includes->include paths->"${workspace_loc:/${ProjName}}" •添加链接库:同上,在cygwin c linker->libraries下添加。 复制代码
3、cygwin warning: MS-DOS style path detected:...
添加环境变量CYGWIN=nodosfilewarning,可取消报警。 复制代码
文末到这里Flutter skia简单应用就介绍到这里。本文主要简介了Flutter学习中的启动流程的 skia引擎他,关于Flutter的学习,还需要学习很多知识点;它的基础语法dart、UI、线程、启动、性能监控。
作者:慢慢529
链接:https://juejin.cn/post/7171314612871102495