安装 Docker Desktop
首先去 Docker 官网下载 macOS 版本的 Docker Desktop 版本(目前(2023/01/06)的最新版本是 4.15.0 (93002)),并安装。
安装 MySQL
通过 Docker Desktop 安装MySQL ,整个过程参考如下:
Mac是苹果自1984年起以“Macintosh”开始的个人消费型计算机,如:iMac、Mac mini、Macbook air、Macbook pro、Mac pro等计算机。使用独立的Mac os系统,最新的OS X系列基于NeXT系统开发,不支持兼容。是一套完备而独立的生态系统。
首先去 Docker 官网下载 macOS 版本的 Docker Desktop 版本(目前(2023/01/06)的最新版本是 4.15.0 (93002)),并安装。
通过 Docker Desktop 安装MySQL ,整个过程参考如下:
1 |
$ sudo mkdir /home/data/timemachine |
netatalk
服务和 avahi-daemon
服务。
1 |
$ sudo apt install netatalk avahi-daemon |
netatalk
的配置文件:
1 |
$ sudo nano /etc/netatalk/afp.conf |
1 2 3 4 5 6 7 |
[TimeCapsule] path = /home/data/timemachine time machine = yes spotlight = no #关闭spotlight索引,这个在Centos6上是不能开的,缺依赖,7上面可以开,但是不建议,吃资源 rwlist = senra #指定某用户有读写权限 force user = senra #强制指定用户 vol size limit = 100000 #限制TM存储容量,单位为MB。 |
1 |
$ sudo service netatalk restart |
现在,你在 TimeMachine 上应该可以看到这个备份服务了,选择该备份服务就可以开始你的第一次备份了。
Intel E3-1230 v3 可以成功安装, AMD Ryzen 5900 CPU 在 Linux 系统上,需要配置 CPU 模仿 Intel CPU 的特性。并且 CPU 部分,不要启用 嵌套VT-x/AMD-V 。
在 macOS (实验使用的系统是 macOS Big Sur (11.7.1))系统上,执行如下命令,生成系统安装镜像
1 2 3 4 5 6 7 8 9 10 11 |
$ hdiutil create -o /tmp/Monterey.cdr -size 15000m -layout SPUD -fs HFS+J $ hdiutil attach /tmp/Monterey.cdr.dmg -noverify -mountpoint /Volumes/install_build $ sudo ~/Install\ macOS\ Monterey.app/Contents/Resources/createinstallmedia --volume /Volumes/install_build $ hdiutil detach /Volumes/Install\ macOS\ Monterey $ mv /tmp/Monterey.cdr.dmg ~/Desktop/InstallSystem.dmg $ hdiutil convert ~/Desktop/InstallSystem.dmg -format UDTO -o ~/Desktop/Monterey.iso |
Writing code for multiple Apple platforms can be tricky, this post aims to provide some guidance and explanations for ways to write code that works on different Apple platforms (iOS, macOS, watchOS, tvOS) and different versions of SDKs, and the OSes at runtime.
First, let’s take a look at how to tell apart the OS you are compiling for at build time, using the preprocessor (in case of Objective-C) or compilation conditions (Swift).
In Swift checking the OS you are building for at comile time is done using compilation conditionals and specific platform condition functions:
The os()
function can be used to check for the OS the code is compiled for, it takes one argument, which is the operating system name (not quoted). Possible operating system names at the time of writing are macOS
, iOS
, tvOS
, watchOS
and Linux
.
For example:
1 2 3 4 5 |
#if os(macOS) // This code is only compiled for macOS #elseif os(iOS) || os(tvOS) // This code is only compiled for iOS or tvOS #endif |
Of course sometimes you need to check if you are running the simualtor or not, to do that there is the targetEnvironment()
function. It takes one argument, which is the target environment name (not quoted). Possible values are simulator
and macCatalyst
(since Swift 5.1).
1 2 3 |
#if os(iOS) && targetEnvironment(simulator) // This code is only compiled for the iOS simulator #endif |
For Objective-C, C and C++ conditional compilation is handled by the preprocessor. Apple provides the TargetConditionals.h
header which contains specific defines for this.
This header has a lot of defines, I will only list the most useful ones here:
TARGET_OS_OSX
TARGET_OS_IOS
TARGET_OS_TV
TARGET_OS_WATCH
TARGET_OS_MACCATALYST
TARGET_OS_SIMULATOR
For example:
1 2 3 4 5 |
#if TARGET_OS_OSX // This code is only compiled for macOS #elif TARGET_OS_IOS || TARGET_OS_TV // This code is only compiled for iOS or tvOS #endif |
To check if compiling for the simulator, just use the TARGET_OS_SIMULATOR
define:
1 2 3 |
#if TARGET_OS_IOS && TARGET_OS_SIMULATOR // This code is only compiled for the iOS simulator #endif |
Note that there is a TARGET_OS_MAC
define, while this sounds like it will be true only for macOS, it is actually true for all Darwin OSes including iOS and tvOS. Another define which can be confusing is the TARGET_OS_IPHONE
, which is actually true for all “mobile” platforms, so iOS, tvOS, watchOS and Catalyst.
Since Clang 6.0 or Xcode 9.3 (r320734) Clang has preprocessor extensions similar to the Swift condition functions which can be used to achieve the same as with the target conditional defines above.
To check the OS code is compiled for, there is the __is_target_os()
preprocessor macro, which takes a single argument, the operating system name. Possible values for Apple OSes are macOS
, iOS
, tvOS
, watchOS
.
For example:
1 2 3 4 5 |
#if __is_target_os(macOS) // This code is only compiled for macOS #elif __is_target_os(iOS) || __is_target_os(tvOS) // This code is only compiled for iOS or tvOS #endif |
To check what environement the code is compiled for, similar to Swift there is the __is_target_environment()
preprocessor macro, which takes as argument the environment name. Possible values are simulator
and macabi
(Catalyst).
1 2 3 |
#if __is_target_os(iOS) && __is_target_environment(simulator) // This code is only compiled for the iOS simulator #endif |
Something that usually is closely related to above discussed conditional compilation is the need to handle API availability gracefully. There are various aspects to consider about API availability, one is API availability at runtime, another is API availability at compile time depending on the used SDK version.
API availability, as the name suggests, means if a specific API (function, class, method, etc.) is actually available.
macOS, iOS, tvOS and watchOS handle API availability in the same way, when a new API is introduced it is annotate with a specific macro that indicates the availability of that API. The macro expands to annotations for the API that indicate how the linker is expected to handle linking to it and can provide additional warnings or errors during compilation when using a deprecated API or trying to use a “too new” API in an application set to run on older appleOS versions that lack this API.
This sounds all very abstract and complex, so let’s have a look at this using an example, the clock_gettime()
function. If we look at the manpage for clock_gettime
we can see that it was introduced in macOS 10.12:
12 HISTORYThese functions first appeared in Mac OSX 10.12
So let’s have a look at how the header declares this function:
1 2 |
__CLOCK_AVAILABILITY int clock_gettime(clockid_t __clock_id, struct timespec *__tp); |
So these functions are annotate with __CLOCK_AVAILABILITY
, which expands to:
1 |
__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0) |
So to be more precise than what the man page tells us, this API is available since macOS 10.12, iOS 10.0, tvOS 10.0 and watchOS 3.0, great!
Of course that still doesn’t provide the full story, to understand what exactly the availability macros do, let’s have a look at the header defining those, Availability.h
. Checking this header, we can see that these macros actually expand to (indirectly using a other macros) use of the availability attribute. I recommend reading this for all the details about how exactly this works. The most important takeaway for the purpose of this article is the following:
A declaration can typically be used even when deploying back to a platform version prior to when the declaration was introduced. When this happens, the declaration is weakly linked, as if the weak_import attribute were added to the declaration. A weakly-linked declaration may or may not be present a run-time, and a program can determine whether the declaration is present by checking whether the address of that declaration is non-NULL.
Note that in addition to the Availability.h
header, there is the AvailabilityMacros.h
header which works similar to the Availability.h
header. Depending on the Framework, it might use either the Availability.h
or the older AvailabilityMacros.h
header.
Now let’s see how we can use such a “partially” avaialble function:
1 2 3 4 5 6 7 8 9 10 |
#include <stdio.h> #include <time.h> int main(int argc, char const *argv[]) { struct timespec value; if (clock_gettime(CLOCK_REALTIME, &value) == 0) { printf("Realtime seconds: %ld\n", value.tv_sec); } } |
If we now compile this targeting macOS 10.14 like that, it just works as expected:
1 2 3 |
$ clang --target=x86_64-apple-macosx10.14 -Wunguarded-availability availability.c && ./a.out Realtime seconds: 1572996298 |
But if we were to try to compile targeting macOS 10.10, we would get a warning:
1 2 3 4 5 6 7 8 9 |
$ clang --target=x86_64-apple-macosx10.10 -Wunguarded-availability availability.c && ./a.out availability.c:7:9: warning: 'clock_gettime' is only available on macOS 10.12 or newer [-Wunguarded-availability] if (clock_gettime(CLOCK_REALTIME, &value) == 0) { ^~~~~~~~~~~~~ […]/usr/include/time.h:178:5: note: 'clock_gettime' has been marked as being introduced in macOS 10.12 here, but the deployment target is macOS 10.10.0 […] Realtime seconds: 1572996508 |
The -Wunguarded-availability
flag is what causes the compiler to emit this warning. For APIs available since macOS 10.13, iOS 11, watchOS 4 and tvOS 11 you will get these warnings even without specifying this flag, as there is a new flag, -Wunguarded-availability-new
which is enabled by default in recent Clang/Xcode versions.
As the name of the warning already gives it away, it only warns about “unguarded” availability, which implies we can “guard” such API usage. There are two ways how this can be done.
The “old” way to check if a partially available function is available would be to check its address:
1 2 3 |
if (&clock_gettime == NULL) { // clock_gettime is not available! } |
Not only is this a bit weird to read, it has some downsides:
Fortunately since some time there is a bette way to handle this! In fact, the compiler would already points this out in the partial availability warning:
note: enclose 'clock_gettime' in a __builtin_available check to silence this warning
So let’s do that:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#include <stdio.h> #include <time.h> int main(int argc, char const *argv[]) { struct timespec value; if (__builtin_available(macOS 10.12, *)) { if (clock_gettime(CLOCK_REALTIME, &value) == 0) { printf("Realtime seconds: %ld\n", value.tv_sec); } } else { // clock_gettime not available! return 1; } } |
And now it will compile without warning again! On macOS at least, that is. We can check multiple platform versions just by listing them all:
1 2 3 |
if (__builtin_available(macOS 10.12, iOS 10.0, *)) { // Running on macOS 10.12 or iOS 10.0 or higher } |
The star at the end is mandatory and means “all other platforms”. So the previous check that just listed macOS would still compile for iOS and crash at runtime when ran on iOS versions lower than iOS 10 which lack clock_gettime
. So take care to cover all cases where the code will run in your availability check!
In Objective-C there is the @available
helper which looks a bit nicer than the longer version from C but is used in the exact same way:
1 2 3 |
if (@available(macOS 10.12, iOS 10.0, *)) { // Running on macOS 10.12 or iOS 10.0 or higher } |
In Swift there is #available
, again the usage is the same except for the different name:
1 2 3 |
if #available(macOS 10.12, iOS 10.0, *) { // Running on macOS 10.12 or iOS 10.0 or higher } |
Note that negating the check or using it together with any other condition is not supported and does not properly guards availability!
Additionally keep in mind that this is a runtime check, so using APIs inside a availability check that are missing in the current SDK version that is compiled with is still an error. To support multiple SDK versions, see the next section for how to check at compile-time!
Sometimes it is necessary to check the availability of a specific API at compile-time, for example when you want to remain compatible with multiple Apple SDKs, where some versions offer new API that you want to use and some versions lack this API.
In the previous section I already mentioned two headers, Availability.h
and AvailabilityMacros.h
. These headers define two important macros:
__<OS-VARIANT>_VERSION_MAX_ALLOWED
__<OS-VARIANT>_VERSION_MIN_REQUIRED
The <OS-VARIANT>
needs to be replaced with the OS variant we want to check for and can be MAC_OS_X
, IPHONE_OS
, TV_OS
or WATCH_OS
.
The above sounds quite abstract so lets illustrate it with a example. Suppose we have a new API introduced for macOS 10.12, so it is first present in the macOS 10.12 SDK. If we were to compile with that SDK, the __MAC_OS_X_VERSION_MAX_ALLOWED
macro is automatically set to the version of the SDK, as that is the maximum macOS version that we can use APIs from, we cannot ever use any APIs newer than the SDK we are using because those are simply not declared. So in case of the 10.12 SDK, __MAC_OS_X_VERSION_MAX_ALLOWED
will be 101200
.
If we want to stay compatible with older SDKs, we can use the following preprocessor macros:
1 2 3 4 5 6 7 8 9 10 |
#include <Availability.h> #if (TARGET_OS_OSX && __MAC_OS_X_VERSION_MAX_ALLOWED >= 101200) if (@available(macOS 10.12, *)) { // Use API available since macOS 10.12 SDK } else { // Fallback to some other API available in 10.11 and older SDKs } #else // Fallback to some other API available in 10.11 and older SDKs #endif |
Note that there are defines for the specific appleOS versions in the availability headers, like __MAC_10_12
so it is tempting to write __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_12
but this will not work because lower SDK versions, like for example the macOS 10.11 SDK will not have the define for higher macOS versions like macOS 10.12!
What is important to note is that the preprocessor checks are done at compile-time, so proper availability handling at runtime is still needed, see the previous section for details about that!
The second macro, __<OS-VARIANT>_VERSION_MIN_REQUIRED
, is useful when you have legacy code that you want to disable when targeting recent enough appleOS versions. Suppose we have function needed for macOS <= 10.11, we can easily disable that when targeting macOS 10.12 or higher by using the __MAC_OS_X_VERSION_MIN_REQUIRED
macro:
1 2 3 4 5 6 |
#include <Availability.h> #if (TARGET_OS_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED <= 101100) void compat_stuff_for_1011() { // ... } #endif |
Of course a lot of other and more complex scenarios are possible with more complex checks, but I won’t cover all of the possibilities here.
Note that the AvailabilityMacros.h
header defines MAC_OS_X_VERSION_MIN_REQUIRED
without the two leading underscores, but the Availability.h
header does not define those. Both define the version with the leading underscores so to prevent confusing code I would recommend to not use the version without the leading underscores.
Note that the above only works for C/C++/Objective-C code, in Swift there is currently no way to check the SDK at compile-time.
Intel E3-1230 v3 可以成功安装, AMD Ryzen 5900 CPU 在 Linux 系统上,需要配置 CPU 模仿 Intel CPU 的特性。并且 CPU 部分,不要启用 嵌套VT-x/AMD-V 。
在 macOS (实验使用的系统是 macOS Big Sur (11.7.1))系统上,执行如下命令,生成系统安装镜像
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
$ hdiutil create -o /tmp/HighSierra.cdr -size 7200m -layout SPUD -fs HFS+J $ hdiutil attach /tmp/HighSierra.cdr.dmg -noverify -mountpoint /Volumes/install_build $ sudo ~/Install\ macOS\ High\ Sierra.app/Contents/Resources/createinstallmedia --volume /Volumes/install_build # 如果安装过程中卡住,查看安装日志,发现有多个安装提供者,无法确定使用哪一个,则必须执行如下命令,更详细的参考下面的解释 $ rm -rf /Volumes/Install\ macOS\ High\ Sierra/Install\ macOS\ High\ Sierra.app/Contents/MacOS $ hdiutil detach /Volumes/Install\ macOS\ High\ Sierra $ mv /tmp/HighSierra.cdr.dmg ~/Desktop/InstallSystem.dmg $ hdiutil convert ~/Desktop/InstallSystem.dmg -format UDTO -o ~/Desktop/HighSierra.iso |
从 RocksDB 7.0 开始,RocksDB 要求编译的 C++ 必须支持 C++ 17 ,( Dropping some compiler support in 7.0#9388)但是目前的Android/iOS版本显然暂时还不能大范围的适配 C++ 17,因此我们目前只能使用 6.x 版本。
Android:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# Android NDK 22.1.7171670 $ brew install git $ brew install cmake $ brew install sed $ git clone https://github.com/facebook/rocksdb.git $ git checkout v6.29.5 # 修改代码,消除警告视为错误,否则会编译不通过 $ gsed -i "s/-Werror//g" CMakeLists.txt # Android最低支持的版本是 Android 23 低于这个版本会出现API缺失导致编译失败 $ cmake . -DCMAKE_ANDROID_NDK=/Users/xxxx/Library/Android/sdk/ndk-bundle \ -DCMAKE_SYSTEM_NAME=Android \ -DCMAKE_SYSTEM_VERSION=23 \ -DCMAKE_ANDROID_STL_TYPE=c++_shared \ -DROCKSDB_LITE=ON \ -DPORTABLE=ON \ -DCMAKE_POSITION_INDEPENDENT_CODE=ON \ -DWITH_TESTS=OFF \ -DWITH_TOOLS=OFF \ -DWITH_GFLAGS=OFF \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a // -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a // -DCMAKE_ANDROID_ARCH_ABI=armeabi-v7a // -DCMAKE_ANDROID_ARCH_ABI=armeabi // -DCMAKE_ANDROID_ARCH_ABI=x86 // -DCMAKE_ANDROID_ARCH_ABI=x86_64 $ make # 在当前目录下生成 # librocksdb.so |
iOS/macOS ARM:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
#Xcode Version 13.2.1 (13C100) $ brew install git $ brew install cmake $ git clone https://github.com/facebook/rocksdb.git $ git checkout v6.29.5 $ export PORTABLE=1 $ export TARGET_OS=IOS $ export ROCKSDB_LITE=1 $ export IOS_CROSS_COMPILE=1 # int128兼容支持,默认支持,但是在iOS设备上是不支持的 $ export TEST_UINT128_COMPAT=1 $ export DISABLE_WARNING_AS_ERROR=1 $ export DEBUG_LEVEL=0 $ export EXTRA_CXXFLAGS="-DNPERF_CONTEXT -DNIOSTATS_CONTEXT" # iOS目前只能构建静态库,不能构建动态库 $ make V=1 VERBOSE=1 -j16 static_lib |
macOS x86:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
#Xcode Version 13.2.1 (13C100) $ brew install git $ brew install cmake $ git clone https://github.com/facebook/rocksdb.git $ git checkout v6.29.5 $ export PORTABLE=1 $ export ROCKSDB_LITE=1 # int128兼容支持,默认支持,但是在iOS设备上是不支持的 $ export TEST_UINT128_COMPAT=1 $ export DISABLE_WARNING_AS_ERROR=1 $ export DEBUG_LEVEL=0 $ export EXTRA_CXXFLAGS="-DNPERF_CONTEXT -DNIOSTATS_CONTEXT" $ make V=1 VERBOSE=1 -j16 static_lib # make V=1 VERBOSE=1 -j16 shared_lib 动态库 |
这篇文章就简单介绍怎么在macOS下使用RocksDB。
RocksDB是一个可嵌入的、持久型的Key-Value存储。
不像MySQL,PostgreSQL这样数据库分客户端与服务器端。实际上,可以把它当作一个第三方库,在自己的代码中进行引用,调用相应的接口就可以使用,比如使用C/C++语言,直接在源代码中include相应的头文件就可以。
与嵌入式数据库SQLite的使用比较类似。
目前: RocksDB使用LSM存储引擎,纯C++编写。Java版本RocksJava也已经完美支持。
更多有关RocksDB的介绍参考:
关于RocksDB的详细使用介绍:
macOS上安装RocksDB非常简单,不用单独安装其他任何依赖。直接使用brew工具安装即可。
1 |
$ brew install rocksdb |
可以运行一下命令来查看安装信息。
1 |
$ brew info rocksdb |
安装结果如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
$ brew info rocksdb rocksdb: stable 7.0.3 (bottled), HEAD Embeddable, persistent key-value store for fast storage https://rocksdb.org/ /usr/local/Cellar/rocksdb/7.0.3 (138 files, 40.4MB) * Poured from bottle on 2022-06-20 at 14:18:52 From: https://mirrors.ustc.edu.cn/homebrew-core.git/Formula/rocksdb.rb License: GPL-2.0-only or Apache-2.0 ==> Dependencies Build: cmake ✔ Required: gflags ✔, lz4 ✔, snappy ✔, zstd ✔ ==> Options --HEAD Install HEAD version ==> Analytics install: 605 (30 days), 2,584 (90 days), 12,941 (365 days) install-on-request: 561 (30 days), 2,247 (90 days), 10,385 (365 days) build-error: 1 (30 days) |
其他操作系统上的安装可以参考:
代码目录:
main.cpp文件内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
#include <iostream> #include <cassert> #include "rocksdb/db.h" using namespace std; int main() { rocksdb::DB* db; rocksdb::Options options; options.create_if_missing = true; rocksdb::Status status = rocksdb::DB::Open(options, "/tmp/testdb", &db); assert(status.ok()); cout << "Open rocksdb success." << endl; string key1 = "1"; string value1 = "aaaaa"; status = db->Put(rocksdb::WriteOptions(), key1, value1); assert(status.ok()); printf("Put[%s,%s] success.\n", key1.c_str(), value1.c_str()); string value; status = db->Get(rocksdb::ReadOptions(), key1, &value); assert(status.ok()); printf("Put key[%s] = %s\n", key1.c_str(), value.c_str()); status = db->Delete(rocksdb::WriteOptions(), key1); assert(status.ok()); printf("Delete key[%s] success.\n", key1.c_str()); delete db; return 0; } |
Makefile文件内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
CXX=g++ -std=c++11 CXXFLAGS=-lrocksdb # 注意添加链接库 all: main main: main.cpp $(CXX) $(CXXFLAGS) -o $@ $< run: main ./main clean: rm -f main *.o |
运行结果:
1 2 3 4 5 6 7 |
make run g++ -std=c++11 -lrocksdb -o main main.cpp ./main Open rocksdb success. Put[1,aaaaa] success. Put key[1] = aaaaa Delete key[1] success. |
系统与开发环境 Flutter (2.10.1~3.3.9)/Xcode 13.2.1(13C100)/macOS Big Sur 11.6.4/iPad Pro(Model A1673) iOS 15.3.1/iPhone SE 3 iOS 16.1.1
1. 苹果开发网站注册或关联开发者账号,如果暂时不需要发布应用到 Mac App Store,只是在设备上调试应用,则不需要注册收费用户,只需要注册或者关联账号即可。具体可以查看官方介绍 选择会员资格 。
2. 在 iPad Pro 和 macbook Pro 登陆同一个注册的开发者的账号。
3. 通过 USB 数据线把 iPad Pro 与 macbook Pro 设备连接起来,如下图:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
$ flutter doctor Doctor summary (to see all details, run flutter doctor -v): [✓] Flutter (Channel stable, 1.22.5, on macOS 11.6.2 20G314 darwin-x64, locale zh-Hans-CN) [!] Android toolchain - develop for Android devices (Android SDK version 30.0.2) ✗ Android license status unknown. Run `flutter doctor --android-licenses` to accept the SDK licenses. See https://flutter.dev/docs/get-started/install/macos#android-setup for more details. [✓] Xcode - develop for iOS and macOS (Xcode 13.2.1) [!] Android Studio (version 2020.3) ✗ Flutter plugin not installed; this adds Flutter specific functionality. ✗ Dart plugin not installed; this adds Dart specific functionality. ✗ Unable to find bundled Java version. [!] IntelliJ IDEA Ultimate Edition (version 2018.3.6) ✗ Flutter plugin not installed; this adds Flutter specific functionality. ✗ Dart plugin not installed; this adds Dart specific functionality. [✓] VS Code (version 1.63.2) [✓] Connected device (1 available) ! Doctor found issues in 3 categories. |
在执行 flutter doctor --android-licenses 的时候报错:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
$ flutter doctor --android-licenses Exception in thread "main" java.lang.NoClassDefFoundError: javax/xml/bind/annotation/XmlSchema at com.android.repository.api.SchemaModule$SchemaModuleVersion.<init>(SchemaModule.java:156) at com.android.repository.api.SchemaModule.<init>(SchemaModule.java:75) at com.android.sdklib.repository.AndroidSdkHandler.<clinit>(AndroidSdkHandler.java:81) at com.android.sdklib.tool.sdkmanager.SdkManagerCli.main(SdkManagerCli.java:73) at com.android.sdklib.tool.sdkmanager.SdkManagerCli.main(SdkManagerCli.java:48) Caused by: java.lang.ClassNotFoundException: javax.xml.bind.annotation.XmlSchema at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581) at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522) ... 5 more |
原因为 Java 版本太高,Flutter 1.22.5 只能使用 Java 1.8版本:
1 2 3 |
$ export JAVA_HOME=/Users/xxxx/Library/Java/JavaVirtualMachines/corretto-1.8.0_312/Contents/Home $ flutter doctor --android-licenses |
对于错误
1 2 3 4 |
[!] Android Studio (version 2020.3) ✗ Flutter plugin not installed; this adds Flutter specific functionality. ✗ Dart plugin not installed; this adds Dart specific functionality. ✗ Unable to find bundled Java version. |
原因:
1 2 3 |
Plugin folder has changed in 4.1 version; From : ~/Library/Application\ Support/AndroidStudio4.1 To: ~/Library/Application\ Support/Google/AndroidStudio4.1/plugins |
Android Studio(4.1)后,安装插件的位置发生了变化,但是flutter doctor
还是去原先的位置找,导致的安装过插件还报错。
解决方法:
1 |
$ ln -s ~/Library/Application\ Support/Google/AndroidStudio2020.3/plugins ~/Library/Application\ Support/AndroidStudio2020.3 |
更简单的方式是执行
1 |
$ flutter upgrade |
升级到 flutter 2.8.1 以及之后的版本即可。
最近,公司的一台电脑升级到 macOS Monterey (12.0.1),之后从进行软件更新,以及 XCode 的下载安装。由于网速的限制,临时把 XCode 的下载进行了暂停操作,之后忘记恢复就进行了重启。
结果第二天在App的安装界面上就看不到被暂停的任务了。然后在 App Store 中尝试继续进行下载,发现无法进行下载任务,下载按钮点击之后,状态一闪而过,又回到待下载状态。
更换账号/重启应用/重启系统之后,无法解决问题。
应该是 App Store 内部状态混乱了,导致无法进行下载任务,需要对 App Store 进行重置操作。
网上搜索很久,才找到解决方案,执行如下命令:
1 |
$ sudo find /private/var/folders/ -iname 'com.apple.appstore' 2>/dev/null | while IFS='' read -r line; do rm -fr "$line"; done; rm -fr ~/Library/Caches/*store*; ps aux | egrep -i 'app.?store' | awk '{ print $2 }' | while IFS='' read -r line; do kill -9 "$line"; done |
之后重启系统,重新点击下载应用,即可解决问题。