kraken上手体验

吐槽君 分类:javascript

阿里的kraken声称能直接用flutter渲染web形态的应用,不仅能实现动态化而且性能也非常不俗,这相当于一个小型浏览器了,于是立马体验了一下。

flutter: 2.0.0
OS: linux
kraken: main@77d74a62
 

当前的kraken还不支持dart的sound null safety, 不过能以兼容模式运行(看看人家做的这迁移!)

按官网的介绍运行先是一坨匪夷所思的报错: 什么error input '... chai:^2.9',折腾半天才发现npm必须得用taobao的源,用nrm解决了,要是不搞web的非前端开发刚接触肯定是懵的。

接着是一个脚本错误,怎么也找不着android sdk的位置:

Error [ERR_UNHANDLED_ERROR]: Unhandled error. ({
  uid: 2,
  name: 'build-android-kraken-lib',
  branch: false,
  error: Error: ENOENT: no such file or directory, scandir '/Users/lindeer/Library/Android/sdk/ndk'
      at Object.readdirSync (fs.js:1021:3)
      at /Users/lindeer/WorkPlace/flutter/projects/kraken/scripts/tasks.js:399:25
      at build-android-kraken-lib (/Users/lindeer/WorkPlace/flutter/projects/kraken/node_modules/undertaker/lib/set-task.js:13:15)
      at bound (domain.js:413:15)
      at runBound (domain.js:424:12)
      at asyncRunner (/Users/lindeer/WorkPlace/flutter/projects/kraken/node_modules/async-done/index.js:55:18)
      at processTicksAndRejections (internal/process/task_queues.js:75:11) {
    errno: -2,
    syscall: 'scandir',
    code: 'ENOENT',
    path: '/Users/lindeer/Library/Android/sdk/ndk',
    domainThrown: true
  },
  duration: [ 0, 1176206 ],
  time: 1617778189523
})
 

不用说这对非安卓的开发也是懵的;原来是因为脚本假定了android sdk的目录在$HOME/Library/Android/sdk,但实际上目录应该取环境变量$ANDROID_HOME或者$ANDROID_SDK_DIR:

diff --git a/scripts/tasks.js b/scripts/tasks.js
index 499d98a6..20690042 100644
--- a/scripts/tasks.js
+++ b/scripts/tasks.js
@@ -391,6 +391,8 @@ task('build-android-kraken-lib', (done) => {
 
   if (platform == 'win32') {
     androidHome = path.join(process.env.LOCALAPPDATA, 'Android\Sdk');
+  } else if (platform == 'linux') {
+    androidHome = process.env.ANDROID_HOME;
   } else {
     androidHome = path.join(process.env.HOME, 'Library/Android/sdk')
   }
 

顺便说一下因为用到了ndk也需要提前安装好ndk,版本在20.0.5594570以上,安装ndk:

$ANDROID_HOME/tools/bin/sdkmanager "ndk;20.0.5594570"
 

最终在目录$ANDROID_HOME/ndk/20.0.5594570/下应该有二进制命令ndk-build

在运行官网的npm run build:bridge:android命令之前最好也做如下的更改,作用主要是改一下获取包的仓库地址,类似npm更改源否则非常容易卡在下载环节让人非常抓狂,要是对安卓开发不熟悉很容易是懵的; 另外cmake的一个写法在linux上总是报错一并更改如下:

diff --git a/kraken/android/gradle/wrapper/gradle-wrapper.properties b/kraken/android/gradle/wrapper/gradle-wrapper.properties
index 01a286e9..41ff4cf2 100644
--- a/kraken/android/gradle/wrapper/gradle-wrapper.properties
+++ b/kraken/android/gradle/wrapper/gradle-wrapper.properties
@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
+distributionUrl=https\://downloads.gradle-dn.com/artifactory/appproduct_dev_local/gradle/gradle-5.6.4-all.zip
diff --git a/kraken/example/android/build.gradle b/kraken/example/android/build.gradle
index e0d7ae2c..93782f98 100644
--- a/kraken/example/android/build.gradle
+++ b/kraken/example/android/build.gradle
@@ -1,7 +1,7 @@
 buildscript {
     repositories {
-        google()
-        jcenter()
+        maven { url 'https://maven.aliyun.com/repository/google' }
+        maven { url 'https://maven.aliyun.com/nexus/content/repositories/jcenter' }
     }
 
     dependencies {
@@ -11,8 +11,8 @@ buildscript {
 
 allprojects {
     repositories {
-        google()
-        jcenter()
+        maven { url 'https://maven.aliyun.com/repository/google' }
+        maven { url 'https://maven.aliyun.com/nexus/content/repositories/jcenter' }
     }
 }
 
diff --git a/kraken/example/android/gradle/wrapper/gradle-wrapper.properties b/kraken/example/android/gradle/wrapper/gradle-wrapper.properties
index 296b146b..39aaae73 100644
--- a/kraken/example/android/gradle/wrapper/gradle-wrapper.properties
+++ b/kraken/example/android/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
+distributionUrl=https\://downloads.gradle-dn.com/artifactory/appproduct_dev_local/gradle/gradle-5.6.4-all.zip

diff --git a/bridge/CMakeLists.txt b/bridge/CMakeLists.txt
index 5d00989b..d5c6816e 100644
--- a/bridge/CMakeLists.txt
+++ b/bridge/CMakeLists.txt
@@ -199,7 +199,7 @@ target_include_directories(kraken PRIVATE
   ${CMAKE_CURRENT_SOURCE_DIR} PUBLIC ./include)
 target_link_libraries(kraken PRIVATE ${BRIDGE_LINK_LIBS})
 
-if (${CMAKE_BUILD_TYPE} STREQUAL "release" OR ${CMAKE_BUILD_TYPE} STREQUAL "relwithdebinfo")
+if ((${CMAKE_BUILD_TYPE} STREQUAL "release") OR (${CMAKE_BUILD_TYPE} STREQUAL "relwithdebinfo"))
   ## http://ptspts.blogspot.com/2013/12/how-to-make-smaller-c-and-c-binaries.html
   ### remove dynamic_cast and exceptions
   target_compile_options(kraken PRIVATE -fno-exceptions -fvisibility=hidden)
 

运行kraken的example示例的时候最好改成

$ flutter devices
3 connected devices:

Pixel (mobile)  • FA69G0304769 • android-arm64  • Android 10 (API 29)
Linux (desktop) • linux        • linux-x64      • Linux
Chrome (web)    • chrome       • web-javascript • Google Chrome 87.0.4280.88
$ cd kraken/example
$ flutter run -v -d FA69G0304769
 

-d是为了指明设备,flutter现在支持多设备有时会自动选择web或者桌面,这时候控制台的输出对flutter不熟悉的开发又是懵的;-v能比较详细的显示编译过程中的细节,如果有错误方便定位.比如flutter2.0会报如下错误但在控制台却可能啥也不输出:

[        ]  - provide a 'noSuchMethod' implementation.
[        ] class ScrollPositionWithSingleContext extends ScrollPosition implements ScrollActivityDelegate {
[        ]       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[        ] /opt/programs/flutter/packages/flutter/lib/src/rendering/viewport_offset.dart:96:12: Context: 'ViewportOffset.hasPixels' is
defined here.
[        ]   bool get hasPixels;
[        ]            ^^^^^^^^^
[ +302 ms] [
 

更改如下:

diff --git a/kraken/lib/src/gesture/scroll_position_with_single_context.dart b/kraken/lib/src/gesture/scroll_position_with_single_context.dart
index 29ffe2af..0717d321 100644
--- a/kraken/lib/src/gesture/scroll_position_with_single_context.dart
+++ b/kraken/lib/src/gesture/scroll_position_with_single_context.dart
@@ -74,6 +74,9 @@ class ScrollPositionWithSingleContext extends ScrollPosition implements ScrollAc
   @override
   AxisDirection get axisDirection => context.axisDirection;
 
+  @override
+  bool get hasPixels => false;
+
   @override
   double setPixels(double newPixels) {
     assert(activity.isScrolling);
 

经历三个领域的懵圈之后应该是能够编译成功并运行kraken_example在设备上了,运行示例是本地js文件kraken/example/assets/bundle.js, 用flutter的devTools可以看到生成的的2个文本对象都是flutter控件:
image.png

然而输入介绍文章中的示例url根本无法运行!直接报如下错误:

[+14652 ms] E/flutter (21723): [ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: NoSuchMethodError: The method
'evalBundle' was called on null.
[        ] E/flutter (21723): Receiver: null
[        ] E/flutter (21723): Tried calling: evalBundle()
[        ] E/flutter (21723): #0      Object.noSuchMethod (dart:core-patch/object_patch.dart:54:5)
[        ] E/flutter (21723): #1      _evalBundle (package:kraken/widget.dart:243:22)
[        ] E/flutter (21723): #2      Kraken.loadURL (package:kraken/widget.dart:75:5)
[        ] E/flutter (21723): <asynchronous suspension>
[        ] E/flutter (21723):
 

它的这个controller是个getter,貌似是缓存:

   KrakenController get controller {
     return KrakenController.getControllerOfName(shortHash(this));
   }
 

等异步回来之后再获取就为null了,改成持有也不行

diff --git a/kraken/lib/widget.dart b/kraken/lib/widget.dart
index b77f7de4..5daeedff 100644
--- a/kraken/lib/widget.dart
+++ b/kraken/lib/widget.dart
   loadURL(String bundleURL) async {
     if (bundleURL == null) return;
-    await controller.unload();
-    await controller.loadBundle(
+    final c = controller;
+    print("--------0 loadURL: $bundleURL");
+    await c.unload();
+    print("--------1 loadURL: $bundleURL");
+    await c.loadBundle(
       bundleURL: bundleURL
     );
-    _evalBundle(controller, animationController);
+    print("--------2 loadURL: $bundleURL");
+    _evalBundle(c, animationController);
   }
 

是用法不对吗,如果直接执行请求回来的js文本呢?也不行,报错如下:

[+16992 ms] E/flutter (22311): [ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: NoSuchMethodError: The method 'unload'
was called on null.
[        ] E/flutter (22311): Receiver: null
[        ] E/flutter (22311): Tried calling: unload()
[        ] E/flutter (22311): #0      Object.noSuchMethod (dart:core-patch/object_patch.dart:54:5)
[        ] E/flutter (22311): #1      Kraken.loadContent (package:kraken/widget.dart:62:22)
[        ] E/flutter (22311): #2      _MyHomePageState.build.<anonymous closure> (package:kraken_example/main.dart:65:24)
[        ] E/flutter (22311): <asynchronous suspension>
[        ] E/flutter (22311):
 

很难说是不是因为flutter2.0的原因导致一些控件行为变化了,看来还有很多的适配工作,目前也没法再体验,难道要开发人员再回退flutter版本吗?!对于我一开始不想了解这太多细节,想立马上手看下效果都这般费劲……

国内的这些kpi开源就有这样的问题,文档不清不楚,预设假定的前提条件太多对开发人员实在是太不友好了;现在压根都不运行测试一下就他娘的开源,开开开,开你娘的屁。

回复

我来回复
  • 暂无回复内容