diff --git a/README_CN.md b/README_CN.md
index 848897fe4ef002fa73e214020de4853c1e9c7339..4985356c617156d90b1ec6e040059a41c0dcb3dd 100644
--- a/README_CN.md
+++ b/README_CN.md
@@ -1,4 +1,7 @@
-# **在线体验暂时下线 !!!**
+2024-04-11 升级到SpringBoot3.0.2
+
+# **在线体验暂时下线**
+
#### 在线文档:[https://ajcaptcha.beliefteam.cn/captcha-doc/](https://ajcaptcha.beliefteam.cn/captcha-doc/ "doc")
[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)[![Total Lines](https://tokei.rs/b1/github/anji-plus/captcha?category=lines)](https://github.com/anji-plus/captcha)
@@ -76,13 +79,20 @@ I Your application is running here: http://localhost:8081
详细的前后端接入文档,后端示例代码service目录下,前端示例代码view目录下。
-# 6 技术支持,如有问题,请提交Issue
-加微信前请备注AJ-Captcha。
-
微信群地址
+# 6 技术支持,如有问题,请提交[Issue](https://gitee.com/anji-plus/captcha/issues)
+
+AJ-Captcha技术支持三群,有问题都可以在群里问
+如果不能直接加进去或者群二维码过期了,请添加下面个人微信
+
+
+
+个人微信:个人微信,不闲聊,加群、咨询请备注,备注格式不限但最好是:“项目名 + 问题”, 项目名可以是**AJ-Captcha**、**Captcha**、**验证码**,只要能一眼分辨就行
+例1:验证码 加群
+例2:captche 有个问题xxxx
+有问题,不管是技术问题还是使用问题,都尽量在群里问,没啥特殊问题尽量别加个人微信。加个人微信记得**一定要加备注 !!!**
+
+
-| 微信 | qq |
-| --- | --- |
-|||
#### 开源不易,劳烦各位star ☺
@@ -92,5 +102,8 @@ I Your application is running here: http://localhost:8081
-# Stargazers over time
+
+
+## Stargazers over time
+
[![Stargazers over time](https://starchart.cc/anji-plus/captcha.svg)](https://starchart.cc/anji-plus/captcha)
diff --git a/core/captcha-spring-boot-starter/pom.xml b/core/captcha-spring-boot-starter/pom.xml
index f0c417818c0371bd1523ad6a3604e9dd6b917a83..95b65d9689ea56c300f775e7a3361962d991764b 100644
--- a/core/captcha-spring-boot-starter/pom.xml
+++ b/core/captcha-spring-boot-starter/pom.xml
@@ -7,7 +7,7 @@
org.springframework.boot
spring-boot-starter-parent
- 2.3.5.RELEASE
+ 3.0.2
com.anji-plus
@@ -20,8 +20,8 @@
jar
- 1.8
- 2.3.5.RELEASE
+ 17
+ 3.0.2
@@ -85,8 +85,8 @@
maven-compiler-plugin
3.3
-
- 1.8
+
+ 17
UTF-8
diff --git a/core/captcha-spring-boot-starter/src/main/java/com/anji/captcha/controller/CaptchaController.java b/core/captcha-spring-boot-starter/src/main/java/com/anji/captcha/controller/CaptchaController.java
index 468833ecd3091e6dc0807b9040dec3a579f6a4ef..8156e0fb9d284749002c306e80ca29de08af2df7 100644
--- a/core/captcha-spring-boot-starter/src/main/java/com/anji/captcha/controller/CaptchaController.java
+++ b/core/captcha-spring-boot-starter/src/main/java/com/anji/captcha/controller/CaptchaController.java
@@ -16,7 +16,7 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
-import javax.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletRequest;
@RestController
diff --git a/core/captcha-spring-boot-starter/src/main/resources/META-INF/spring.factories b/core/captcha-spring-boot-starter/src/main/resources/META-INF/spring.factories
deleted file mode 100644
index 218ca002bbfb20df68c06df396b1135f997077e7..0000000000000000000000000000000000000000
--- a/core/captcha-spring-boot-starter/src/main/resources/META-INF/spring.factories
+++ /dev/null
@@ -1 +0,0 @@
-org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.anji.captcha.config.AjCaptchaAutoConfiguration
\ No newline at end of file
diff --git a/core/captcha-spring-boot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/core/captcha-spring-boot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 0000000000000000000000000000000000000000..4a295be86e25d9c5546ea2d19388f836d9e1a1ba
--- /dev/null
+++ b/core/captcha-spring-boot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1 @@
+com.anji.captcha.config.AjCaptchaAutoConfiguration
diff --git a/core/captcha/pom.xml b/core/captcha/pom.xml
index c9585dc9cef984bc09d9f75bff72ce2f47ac42ab..8394cd59ff0246db10d9b3d16f66c93fdbc91c48 100644
--- a/core/captcha/pom.xml
+++ b/core/captcha/pom.xml
@@ -16,7 +16,7 @@
UTF-8
UTF-8
- 1.8
+ 17
@@ -24,7 +24,7 @@
org.slf4j
slf4j-api
- 1.7.25
+ 2.0.2
provided
@@ -51,7 +51,6 @@
https://github.com/anji-plus
-
snapshots
@@ -65,8 +64,8 @@
maven-compiler-plugin
3.3
-
- 1.8
+
+ 17
UTF-8
diff --git "a/images/\346\273\221\345\212\250\346\213\274\345\233\276.gif" "b/images/\346\273\221\345\212\250\346\213\274\345\233\276.gif"
new file mode 100644
index 0000000000000000000000000000000000000000..0f170423bc1aa339e1d79e50aaf508b02db339a0
Binary files /dev/null and "b/images/\346\273\221\345\212\250\346\213\274\345\233\276.gif" differ
diff --git "a/images/\347\202\271\351\200\211\346\226\207\345\255\227.gif" "b/images/\347\202\271\351\200\211\346\226\207\345\255\227.gif"
new file mode 100644
index 0000000000000000000000000000000000000000..0910b153794ce25e5a1638fe2d1b9c5a4774222f
Binary files /dev/null and "b/images/\347\202\271\351\200\211\346\226\207\345\255\227.gif" differ
diff --git a/pom.xml b/pom.xml
index ac7634024984c73afaf739069040fd8a0b2fea68..97c7f587ddf93d450488352a6b5b592fdf5fc204 100644
--- a/pom.xml
+++ b/pom.xml
@@ -10,10 +10,10 @@
pom
- 2.0.4.RELEASE
+ 3.0.2
1.2.0
- 1.8
- 1.8
+ 17
+ 17
UTF-8
@@ -43,6 +43,18 @@
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ 17
+
+
+
+
core/captcha
core/captcha-spring-boot-starter
diff --git a/service/php/readme.md b/service/php/readme.md
index 1c9a8256aaae5628135be4e623320408ce25927f..bd122260834865c2d17125776e820800431097b9 100644
--- a/service/php/readme.md
+++ b/service/php/readme.md
@@ -27,6 +27,12 @@ test 目录下示例了三种使用方式,phper可以参考使用。[查看dem
2. 基于框架使用的场景,输入安装命令`composer require fastknife/ajcaptcha`(稳定版) 或者`composer require fastknife/ajcaptcha dev-master`(最新版) ,建议使用composer阿里源(`https://mirrors.aliyun.com/composer`)
* 支持各种前沿框架(ThinkPHP, YII, Laravel, Hyperf,IMI,Swoft,EasySwoole)
* 本软件包内,未使用单例、注册树(容器)模式,不含任何全局变量,基于swoole开发的同学不用担心内存泄露。
+
+3. 以thinkphp框架后端和vue框架前端为例,在本地开发环境运行起示例项目说明:
+3.1 开启命令行窗口,进入 captcha\service\php\test\thinkphp 目录,执行 `composer install` 命令安装依赖,执行 `php think run` 命令启动接口服务。
+3.2 修改 captcha\view\vue\config\dev.env.js 中 BASE_API: '"http://localhost:8000"' ,取值与 3.1中启动的接口服务地址一致。
+3.3 开启命令行窗口,进入 captcha\view\vue 目录,执行 `npm install` 命令安装依赖,执行 `npm run dev` 命令启动前端项目。
+
#### 项目结构
> 本软件包基于整洁架构理念,设计了下文的目录结构。Domain(领域层)作为内层同心圆承担所有业务逻辑功能,Service(服务层)并向最外层Controller(需自行实现)提供粗颗粒度服务。
diff --git a/service/php/test/thinkphp/app/controller/Index.php b/service/php/test/thinkphp/app/controller/Index.php
index a773762f25c4d1ab278c8db55213e3936a99c8fd..0494b638391a315120f2c9ef0dd5e9c410f943f6 100644
--- a/service/php/test/thinkphp/app/controller/Index.php
+++ b/service/php/test/thinkphp/app/controller/Index.php
@@ -21,6 +21,16 @@ class Index
} catch (\Exception $e) {
$this->error($e->getMessage());
}
+ /* 如果开发框架开启了debug、trace,导致前端项目无法正确获取到后台接口的返回数据,可以修改为本注释内的接口返回方式
+ $response = [
+ 'error' => false,
+ 'repCode' => '0000',
+ 'repData' => $data,
+ 'repMsg' => null,
+ 'success' => true,
+ ];
+ return json($response);*/
+
$this->success($data);
}
@@ -34,6 +44,15 @@ class Index
} catch (\Exception $e) {
$this->error($e->getMessage());
}
+ /* 如果开发框架开启了debug、trace,导致前端项目无法正确获取到后台接口的返回数据,可以修改为本注释内的接口返回方式
+ $response = [
+ 'error' => false,
+ 'repCode' => '0000',
+ 'repData' => [],
+ 'repMsg' => null,
+ 'success' => true,
+ ];
+ return json($response);*/
$this->success([]);
}
diff --git a/service/php/test/thinkphp/config/route.php b/service/php/test/thinkphp/config/route.php
new file mode 100644
index 0000000000000000000000000000000000000000..955eeec0eb63b906922972d096cc2972839a53b7
--- /dev/null
+++ b/service/php/test/thinkphp/config/route.php
@@ -0,0 +1,45 @@
+ '/',
+ // URL伪静态后缀
+ 'url_html_suffix' => 'html',
+ // URL普通方式参数 用于自动生成
+ 'url_common_param' => true,
+ // 是否开启路由延迟解析
+ 'url_lazy_route' => false,
+ // 是否强制使用路由
+ 'url_route_must' => false,
+ // 合并路由规则
+ 'route_rule_merge' => false,
+ // 路由是否完全匹配
+ 'route_complete_match' => false,
+ // 访问控制器层名称
+ 'controller_layer' => 'controller',
+ // 空控制器名
+ 'empty_controller' => 'Error',
+ // 是否使用控制器后缀
+ 'controller_suffix' => false,
+ // 默认的路由变量规则
+ 'default_route_pattern' => '[\w\.]+',
+ // 是否开启请求缓存 true自动缓存 支持设置请求缓存规则
+ 'request_cache' => false,
+ // 请求缓存有效期
+ 'request_cache_expire' => null,
+ // 全局请求缓存排除规则
+ 'request_cache_except' => [],
+ // 默认控制器名
+ 'default_controller' => 'Index',
+ // 默认操作名
+ 'default_action' => 'index',
+ // 操作方法后缀
+ 'action_suffix' => '',
+ // 默认JSONP格式返回的处理方法
+ 'default_jsonp_handler' => 'jsonpReturn',
+ // 默认JSONP处理方法
+ 'var_jsonp_handler' => 'callback',
+];
diff --git a/service/php/test/thinkphp/route/app.php b/service/php/test/thinkphp/route/app.php
new file mode 100644
index 0000000000000000000000000000000000000000..e82de9196b279b0ec13825a919d2725cae1bca51
--- /dev/null
+++ b/service/php/test/thinkphp/route/app.php
@@ -0,0 +1,18 @@
+
+// +----------------------------------------------------------------------
+use think\facade\Route;
+
+Route::get('think', function () {
+ return 'hello,ThinkPHP6!';
+});
+
+Route::post('/captcha/get', 'Index/index')->allowCrossDomain();
+Route::post('/captcha/check', 'Index/check')->allowCrossDomain();
\ No newline at end of file
diff --git a/service/springboot/pom.xml b/service/springboot/pom.xml
index 54bd33a21f7e7d301352b4b46e3a00aa3c5a634a..7e83a1c5d7e5baabf44b1214649d7b8ef0f67afa 100644
--- a/service/springboot/pom.xml
+++ b/service/springboot/pom.xml
@@ -7,7 +7,7 @@
org.springframework.boot
spring-boot-starter-parent
- 2.3.5.RELEASE
+ 3.0.2
com.anji.captcha
@@ -20,8 +20,8 @@
jar
- 1.8
- 2.3.5.RELEASE
+ 17
+ 3.0.2
true
@@ -61,6 +61,13 @@
+
+
+ junit
+ junit
+ 4.11
+ test
+
@@ -70,6 +77,14 @@
org.springframework.boot
spring-boot-maven-plugin
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ 17
+
+
diff --git a/service/springboot/src/main/java/com/anji/captcha/demo/filter/CorsFilter.java b/service/springboot/src/main/java/com/anji/captcha/demo/filter/CorsFilter.java
index f6840794aae2ea1c5133d2a977f34e9bce684902..ff36e7c48612af0a09ade6e7cd8930514e4a1954 100644
--- a/service/springboot/src/main/java/com/anji/captcha/demo/filter/CorsFilter.java
+++ b/service/springboot/src/main/java/com/anji/captcha/demo/filter/CorsFilter.java
@@ -12,10 +12,10 @@ package com.anji.captcha.demo.filter;
*/
import org.springframework.context.annotation.Configuration;
-import javax.servlet.*;
-import javax.servlet.annotation.WebFilter;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import jakarta.servlet.*;
+import jakarta.servlet.annotation.WebFilter;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter(filterName = "CorsFilter ")
diff --git a/service/springmvc/pom.xml b/service/springmvc/pom.xml
index 351af8cd1a446b24d30e43edbd32e7ca6915e778..1963c801d3fcde7be7a5c843e40dee3609d13774 100644
--- a/service/springmvc/pom.xml
+++ b/service/springmvc/pom.xml
@@ -1,7 +1,7 @@
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
com.anjiplus.demo
@@ -14,12 +14,12 @@
UTF-8
- 1.7
- 1.7
+ 17
+ 17
1.8
1.6.6
1.2.12
- 5.0.16.RELEASE
+ 6.0.4
@@ -33,7 +33,7 @@
com.anji-plus
captcha
- 1.2.9
+ 1.3.1
com.alibaba
@@ -96,13 +96,13 @@
org.slf4j
slf4j-api
- 1.7.25
+ 2.0.2
org.slf4j
slf4j-log4j12
- 1.7.25
+ 2.0.2
@@ -114,7 +114,7 @@
org.springframework.data
spring-data-redis
- 1.8.1.RELEASE
+ 3.0.1
diff --git a/view/doc/docs/README.md b/view/doc/docs/README.md
index 60f5bd760af44dcdfd41111cea1c352fbb2c222d..b2c3e4a38372ad5a3020940b6dcf147f5c74d675 100644
--- a/view/doc/docs/README.md
+++ b/view/doc/docs/README.md
@@ -1,21 +1,9 @@
-# 在线体验
-#### 1.1 电脑在线体验:[https://captcha.anji-plus.com/](https://captcha.anji-plus.com/ "链接")
-#### 1.2 在线文档:[https://captcha.anji-plus.com/#/doc](https://captcha.anji-plus.com/#/doc "doc")
-#### 1.3 微信小程序和H5在线体验(基于uni-app实现)
- 如果图片未能正常展示,可查看码云,和github同步 [码云]( https://gitee.com/anji-plus/captcha "码云")
-![微信小程序](https://captcha.anji-plus.com/static/8cm.jpg "微信小程序")
- 微信小程序Demo
# 功能概述
#### 2.1 组件介绍
行为验证码采用嵌入式集成方式,接入方便,安全,高效。抛弃了传统字符型验证码展示-填写字符-比对答案的流程,采用验证码展示-采集用户行为-分析用户行为流程,用户只需要产生指定的行为轨迹,不需要键盘手动输入,极大优化了传统验证码用户体验不佳的问题;同时,快速、准确的返回人机判定结果。目前对外提供两种类型的验证码,其中包含滑动拼图、文字点选。如图1-1、1-2所示。若希望不影响原UI布局,可采用弹出式交互。
后端基于Java实现,提供纯Java.jar和SpringBoot Starter。前端提供了Android、iOS、Futter、Uni-App、ReactNative、Vue、Angular、Html、Php等多端示例。
-| 滑动拼图 | 文字点选 |
-| --- | --- |
-|![滑动拼图](https://captcha.anji-plus.com/static/blockPuzzle.png "滑动拼图") |![点选文字](https://captcha.anji-plus.com/static/clickWord.png "点选文字")|
-| 图1-1 | 图1-2 |
-
#### 2.2 概念术语描述
| 术语 | 描述 |
@@ -30,7 +18,7 @@
③ 用户提交表单,前端将第二步的输出一同提交到后台
④ 验证数据随表单提交到后台后,后台需要调用captchaService.verification做二次校验。
⑤ 第4步返回校验通过/失败到产品应用后端,再返回到前端。如下图所示。
-![时序图](https://captcha.anji-plus.com/static/shixu.png "时序图")
+
# 目录结构
├─core
@@ -66,14 +54,6 @@ I Your application is running here: http://localhost:8081
详细的前后端接入文档,后端示例代码service目录下,前端示例代码view目录下。
-# 近期计划
-#### 6.1 增加weex示例
-#### 6.2 增加ReactNative示例(已添加)
-
-# 技术支持微信群
-微信一群已满,现开放二群。github可能有缓存,不会自动更新。
-
微信群地址:https://captcha.anji-plus.com/static/weixin.png
-
#### 开源不易,劳烦各位star ☺
diff --git a/view/flutter/demo/ios/Flutter/AppFrameworkInfo.plist b/view/flutter/demo/ios/Flutter/AppFrameworkInfo.plist
index 6b4c0f78a7850094f62713858e533a2fc8eda617..f2872cf474eee0cc0439d4012e1a653ac08e9d0f 100644
--- a/view/flutter/demo/ios/Flutter/AppFrameworkInfo.plist
+++ b/view/flutter/demo/ios/Flutter/AppFrameworkInfo.plist
@@ -21,6 +21,6 @@
CFBundleVersion
1.0
MinimumOSVersion
- 8.0
+ 9.0
diff --git a/view/flutter/demo/ios/Runner.xcodeproj/project.pbxproj b/view/flutter/demo/ios/Runner.xcodeproj/project.pbxproj
index 3705ccabe4f327442e82a3a73ed94e32f982392c..d63af51b714e5bee96a8e9bdd11641c951c2218b 100644
--- a/view/flutter/demo/ios/Runner.xcodeproj/project.pbxproj
+++ b/view/flutter/demo/ios/Runner.xcodeproj/project.pbxproj
@@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
- objectVersion = 46;
+ objectVersion = 50;
objects = {
/* Begin PBXBuildFile section */
@@ -135,7 +135,7 @@
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 1020;
+ LastUpgradeCheck = 1300;
ORGANIZATIONNAME = "The Chromium Authors";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
@@ -241,7 +241,6 @@
/* Begin XCBuildConfiguration section */
249021D3217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
@@ -281,7 +280,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
@@ -318,7 +317,6 @@
};
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
@@ -364,7 +362,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -374,7 +372,6 @@
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
@@ -414,7 +411,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
diff --git a/view/flutter/demo/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/view/flutter/demo/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
index 1d526a16ed0f1cd0c2409d848bf489b93fefa3b2..919434a6254f0e9651f402737811be6634a03e9c 100644
--- a/view/flutter/demo/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
+++ b/view/flutter/demo/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -2,6 +2,6 @@
+ location = "self:">
diff --git a/view/flutter/demo/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/view/flutter/demo/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
index a28140cfdb3ff9b7a11a9497b84546d615db2afa..3db53b6e1fb7f8a5fae6c2e6eb4e3b4382a3691e 100644
--- a/view/flutter/demo/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
+++ b/view/flutter/demo/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -1,6 +1,6 @@
UIViewControllerBasedStatusBarAppearance
+ CADisableMinimumFrameDurationOnPhone
+
diff --git a/view/flutter/demo/lib/request/HttpManager.dart b/view/flutter/demo/lib/request/HttpManager.dart
index 711b9c6a647344c0b204e459713d256f1fee66c2..80bc84064a7a32ad8cf905db206155c58001d422 100644
--- a/view/flutter/demo/lib/request/HttpManager.dart
+++ b/view/flutter/demo/lib/request/HttpManager.dart
@@ -14,8 +14,8 @@ class HttpManager {
"content-Type": CONTENT_TYPE_JSON
};
//请求base url
-// static String baseUrl = "http://10.108.11.46:8080/api";
- static String baseUrl = "https://captcha.anji-plus.com/captcha-api";
+ static String baseUrl = "http://127.0.0.1:8080";
+// static String baseUrl = "https://captcha.anji-plus.com/captcha-api";
///发起网络请求
///[ url] 请求url
diff --git a/view/flutter/demo/pubspec.lock b/view/flutter/demo/pubspec.lock
index c25ade49779af5381d0ec5283122992a45ca614e..08ee1ce8a409f4f16a8144fd98caa0ba3cd6840d 100644
--- a/view/flutter/demo/pubspec.lock
+++ b/view/flutter/demo/pubspec.lock
@@ -5,86 +5,100 @@ packages:
dependency: transitive
description:
name: args
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
- version: "1.5.2"
+ version: "1.6.0"
asn1lib:
dependency: transitive
description:
name: asn1lib
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
- version: "0.5.15"
+ version: "0.6.5"
async:
dependency: transitive
description:
name: async
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
- version: "2.3.0"
+ version: "2.8.2"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
- version: "1.0.5"
+ version: "2.1.0"
+ characters:
+ dependency: transitive
+ description:
+ name: characters
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.2.0"
charcode:
dependency: transitive
description:
name: charcode
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
- version: "1.1.2"
+ version: "1.3.1"
clock:
dependency: transitive
description:
name: clock
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
- version: "1.0.1"
+ version: "1.1.0"
collection:
dependency: transitive
description:
name: collection
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
- version: "1.14.11"
+ version: "1.16.0"
convert:
dependency: transitive
description:
name: convert
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
crypto:
dependency: transitive
description:
name: crypto
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
- version: "2.1.3"
+ version: "2.1.5"
cupertino_icons:
dependency: "direct main"
description:
name: cupertino_icons
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "0.1.3"
dio:
dependency: "direct main"
description:
name: dio
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
- version: "3.0.9"
+ version: "3.0.10"
encrypt:
dependency: "direct main"
description:
name: encrypt
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
- version: "4.0.0"
+ version: "4.0.3"
+ fake_async:
+ dependency: transitive
+ description:
+ name: fake_async
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.3.0"
flutter:
dependency: "direct main"
description: flutter
@@ -99,51 +113,44 @@ packages:
dependency: transitive
description:
name: http_parser
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
- version: "3.1.3"
+ version: "3.1.4"
matcher:
dependency: transitive
description:
name: matcher
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "0.12.11"
+ material_color_utilities:
+ dependency: transitive
+ description:
+ name: material_color_utilities
+ url: "https://pub.dartlang.org"
source: hosted
- version: "0.12.5"
+ version: "0.1.4"
meta:
dependency: transitive
description:
name: meta
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
- version: "1.1.7"
+ version: "1.7.0"
path:
dependency: transitive
description:
name: path
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
- version: "1.6.4"
- pedantic:
- dependency: transitive
- description:
- name: pedantic
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "1.8.0+1"
+ version: "1.8.1"
pointycastle:
dependency: transitive
description:
name: pointycastle
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
- quiver:
- dependency: transitive
- description:
- name: quiver
- url: "https://pub.flutter-io.cn"
- source: hosted
- version: "2.0.5"
sky_engine:
dependency: transitive
description: flutter
@@ -153,64 +160,64 @@ packages:
dependency: transitive
description:
name: source_span
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
- version: "1.5.5"
+ version: "1.8.2"
stack_trace:
dependency: transitive
description:
name: stack_trace
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
- version: "1.9.3"
+ version: "1.10.0"
steel_crypt:
dependency: "direct main"
description:
name: steel_crypt
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
- version: "1.5.4"
+ version: "1.7.1+1"
stream_channel:
dependency: transitive
description:
name: stream_channel
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
- version: "2.0.0"
+ version: "2.1.0"
string_scanner:
dependency: transitive
description:
name: string_scanner
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
- version: "1.0.5"
+ version: "1.1.0"
term_glyph:
dependency: transitive
description:
name: term_glyph
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
- version: "1.1.0"
+ version: "1.2.0"
test_api:
dependency: transitive
description:
name: test_api
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
- version: "0.2.5"
+ version: "0.4.9"
typed_data:
dependency: transitive
description:
name: typed_data
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
- version: "1.1.6"
+ version: "1.3.1"
vector_math:
dependency: transitive
description:
name: vector_math
- url: "https://pub.flutter-io.cn"
+ url: "https://pub.dartlang.org"
source: hosted
- version: "2.0.8"
+ version: "2.1.2"
sdks:
- dart: ">2.4.0 <3.0.0"
+ dart: ">=2.17.0-0 <3.0.0"
diff --git a/view/flutter/demo_null_safety/.gitignore b/view/flutter/demo_null_safety/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..8786b9410f4d39e9c8d0a11f8806a8c31aad3fd4
--- /dev/null
+++ b/view/flutter/demo_null_safety/.gitignore
@@ -0,0 +1,4 @@
+/.dart_tool/
+/.idea/
+/build/
+.packages
\ No newline at end of file
diff --git a/view/flutter/demo_null_safety/README.md b/view/flutter/demo_null_safety/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..40905729cfcdcd29f5db475b3fee304126a2a387
--- /dev/null
+++ b/view/flutter/demo_null_safety/README.md
@@ -0,0 +1,16 @@
+# captcha
+
+A new Flutter application.
+
+## Getting Started
+
+This project is a starting point for a Flutter application.
+
+A few resources to get you started if this is your first Flutter project:
+
+- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab)
+- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook)
+
+For help getting started with Flutter, view our
+[online documentation](https://flutter.dev/docs), which offers tutorials,
+samples, guidance on mobile development, and a full API reference.
diff --git a/view/flutter/demo_null_safety/android/.gitignore b/view/flutter/demo_null_safety/android/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..bc2100d8f75e6efef413729756e448e910f7304d
--- /dev/null
+++ b/view/flutter/demo_null_safety/android/.gitignore
@@ -0,0 +1,7 @@
+gradle-wrapper.jar
+/.gradle
+/captures/
+/gradlew
+/gradlew.bat
+/local.properties
+GeneratedPluginRegistrant.java
diff --git a/view/flutter/demo_null_safety/android/app/build.gradle b/view/flutter/demo_null_safety/android/app/build.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..acf469b36241a0c0ab5f3ddf16afd7c3a09dc174
--- /dev/null
+++ b/view/flutter/demo_null_safety/android/app/build.gradle
@@ -0,0 +1,75 @@
+def localProperties = new Properties()
+def localPropertiesFile = rootProject.file('local.properties')
+if (localPropertiesFile.exists()) {
+ localPropertiesFile.withReader('UTF-8') { reader ->
+ localProperties.load(reader)
+ }
+}
+
+def flutterRoot = localProperties.getProperty('flutter.sdk')
+if (flutterRoot == null) {
+ throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
+}
+
+def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
+if (flutterVersionCode == null) {
+ flutterVersionCode = '1'
+}
+
+def flutterVersionName = localProperties.getProperty('flutter.versionName')
+if (flutterVersionName == null) {
+ flutterVersionName = '1.0'
+}
+
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
+
+android {
+ compileSdkVersion 28
+
+ sourceSets {
+ main.java.srcDirs += 'src/main/kotlin'
+ }
+
+ lintOptions {
+ disable 'InvalidPackage'
+ }
+
+ defaultConfig {
+ // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
+ applicationId "com.anjiplus.captcha"
+ minSdkVersion 16
+ targetSdkVersion 28
+ versionCode flutterVersionCode.toInteger()
+ versionName flutterVersionName
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+
+ ndk {
+ abiFilters 'armeabi-v7a','x86'
+ }
+ }
+
+ buildTypes {
+ release {
+ // TODO: Add your own signing config for the release build.
+ // Signing with the debug keys for now, so `flutter run --release` works.
+ signingConfig signingConfigs.debug
+
+ ndk {
+ abiFilters 'armeabi-v7a'
+ }
+ }
+ }
+}
+
+flutter {
+ source '../..'
+}
+
+dependencies {
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+ testImplementation 'junit:junit:4.12'
+ androidTestImplementation 'androidx.test:runner:1.1.1'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
+}
diff --git a/view/flutter/demo_null_safety/android/app/src/debug/AndroidManifest.xml b/view/flutter/demo_null_safety/android/app/src/debug/AndroidManifest.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ba4ee87a2fc9f25967ca6df8b1213b93b6fdd881
--- /dev/null
+++ b/view/flutter/demo_null_safety/android/app/src/debug/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/view/flutter/demo_null_safety/android/app/src/main/AndroidManifest.xml b/view/flutter/demo_null_safety/android/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000000000000000000000000000000000..40685f6690352fb5f55b4edf9d601746d6b49555
--- /dev/null
+++ b/view/flutter/demo_null_safety/android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/view/flutter/demo_null_safety/android/app/src/main/kotlin/com/anjiplus/captcha/MainActivity.kt b/view/flutter/demo_null_safety/android/app/src/main/kotlin/com/anjiplus/captcha/MainActivity.kt
new file mode 100644
index 0000000000000000000000000000000000000000..ae94e2312c009b35549677e8f4ff92bd156af328
--- /dev/null
+++ b/view/flutter/demo_null_safety/android/app/src/main/kotlin/com/anjiplus/captcha/MainActivity.kt
@@ -0,0 +1,12 @@
+package com.anjiplus.captcha
+
+import androidx.annotation.NonNull;
+import io.flutter.embedding.android.FlutterActivity
+import io.flutter.embedding.engine.FlutterEngine
+import io.flutter.plugins.GeneratedPluginRegistrant
+
+class MainActivity: FlutterActivity() {
+ override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
+ GeneratedPluginRegistrant.registerWith(flutterEngine);
+ }
+}
diff --git a/view/flutter/demo_null_safety/android/app/src/main/res/drawable/launch_background.xml b/view/flutter/demo_null_safety/android/app/src/main/res/drawable/launch_background.xml
new file mode 100644
index 0000000000000000000000000000000000000000..304732f8842013497e14bd02f67a55f2614fb8f7
--- /dev/null
+++ b/view/flutter/demo_null_safety/android/app/src/main/res/drawable/launch_background.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/view/flutter/demo_null_safety/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/view/flutter/demo_null_safety/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000000000000000000000000000000000000..db77bb4b7b0906d62b1847e87f15cdcacf6a4f29
Binary files /dev/null and b/view/flutter/demo_null_safety/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/view/flutter/demo_null_safety/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/view/flutter/demo_null_safety/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000000000000000000000000000000000000..17987b79bb8a35cc66c3c1fd44f5a5526c1b78be
Binary files /dev/null and b/view/flutter/demo_null_safety/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/view/flutter/demo_null_safety/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/view/flutter/demo_null_safety/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000000000000000000000000000000000000..09d4391482be68e9e4a07fab769b5de337d16eb1
Binary files /dev/null and b/view/flutter/demo_null_safety/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/view/flutter/demo_null_safety/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/view/flutter/demo_null_safety/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000000000000000000000000000000000000..d5f1c8d34e7a88e3f88bea192c3a370d44689c3c
Binary files /dev/null and b/view/flutter/demo_null_safety/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/view/flutter/demo_null_safety/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/view/flutter/demo_null_safety/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000000000000000000000000000000000000..4d6372eebdb28e45604e46eeda8dd24651419bc0
Binary files /dev/null and b/view/flutter/demo_null_safety/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/view/flutter/demo_null_safety/android/app/src/main/res/values/styles.xml b/view/flutter/demo_null_safety/android/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000000000000000000000000000000000000..00fa4417cfbef8673c47c86eb24033fcd97056a8
--- /dev/null
+++ b/view/flutter/demo_null_safety/android/app/src/main/res/values/styles.xml
@@ -0,0 +1,8 @@
+
+
+
+
diff --git a/view/flutter/demo_null_safety/android/app/src/profile/AndroidManifest.xml b/view/flutter/demo_null_safety/android/app/src/profile/AndroidManifest.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ba4ee87a2fc9f25967ca6df8b1213b93b6fdd881
--- /dev/null
+++ b/view/flutter/demo_null_safety/android/app/src/profile/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/view/flutter/demo_null_safety/android/build.gradle b/view/flutter/demo_null_safety/android/build.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..3100ad2d55532e58ed44b53dd3c2a04c5bcaf160
--- /dev/null
+++ b/view/flutter/demo_null_safety/android/build.gradle
@@ -0,0 +1,31 @@
+buildscript {
+ ext.kotlin_version = '1.3.50'
+ repositories {
+ google()
+ jcenter()
+ }
+
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.5.0'
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+ }
+}
+
+rootProject.buildDir = '../build'
+subprojects {
+ project.buildDir = "${rootProject.buildDir}/${project.name}"
+}
+subprojects {
+ project.evaluationDependsOn(':app')
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/view/flutter/demo_null_safety/android/gradle.properties b/view/flutter/demo_null_safety/android/gradle.properties
new file mode 100644
index 0000000000000000000000000000000000000000..38c8d4544ff1c4419409796aa6c1caee2c262ff7
--- /dev/null
+++ b/view/flutter/demo_null_safety/android/gradle.properties
@@ -0,0 +1,4 @@
+org.gradle.jvmargs=-Xmx1536M
+android.enableR8=true
+android.useAndroidX=true
+android.enableJetifier=true
diff --git a/view/flutter/demo_null_safety/android/gradle/wrapper/gradle-wrapper.properties b/view/flutter/demo_null_safety/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000000000000000000000000000000000000..296b146b7318dd58663296dbb7555df9ff328ec2
--- /dev/null
+++ b/view/flutter/demo_null_safety/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Fri Jun 23 08:50:38 CEST 2017
+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
diff --git a/view/flutter/demo_null_safety/android/settings.gradle b/view/flutter/demo_null_safety/android/settings.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..5a2f14fb18f6e8b8c4308ff0f0dc187d9d27a5aa
--- /dev/null
+++ b/view/flutter/demo_null_safety/android/settings.gradle
@@ -0,0 +1,15 @@
+include ':app'
+
+def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
+
+def plugins = new Properties()
+def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
+if (pluginsFile.exists()) {
+ pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
+}
+
+plugins.each { name, path ->
+ def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
+ include ":$name"
+ project(":$name").projectDir = pluginDirectory
+}
diff --git a/view/flutter/demo_null_safety/ios/.gitignore b/view/flutter/demo_null_safety/ios/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..e96ef602b8d172f7cd28ba656aac097f741c736d
--- /dev/null
+++ b/view/flutter/demo_null_safety/ios/.gitignore
@@ -0,0 +1,32 @@
+*.mode1v3
+*.mode2v3
+*.moved-aside
+*.pbxuser
+*.perspectivev3
+**/*sync/
+.sconsign.dblite
+.tags*
+**/.vagrant/
+**/DerivedData/
+Icon?
+**/Pods/
+**/.symlinks/
+profile
+xcuserdata
+**/.generated/
+Flutter/App.framework
+Flutter/Flutter.framework
+Flutter/Flutter.podspec
+Flutter/Generated.xcconfig
+Flutter/app.flx
+Flutter/app.zip
+Flutter/flutter_assets/
+Flutter/flutter_export_environment.sh
+ServiceDefinitions.json
+Runner/GeneratedPluginRegistrant.*
+
+# Exceptions to above rules.
+!default.mode1v3
+!default.mode2v3
+!default.pbxuser
+!default.perspectivev3
diff --git a/view/flutter/demo_null_safety/ios/Flutter/AppFrameworkInfo.plist b/view/flutter/demo_null_safety/ios/Flutter/AppFrameworkInfo.plist
new file mode 100644
index 0000000000000000000000000000000000000000..f2872cf474eee0cc0439d4012e1a653ac08e9d0f
--- /dev/null
+++ b/view/flutter/demo_null_safety/ios/Flutter/AppFrameworkInfo.plist
@@ -0,0 +1,26 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleExecutable
+ App
+ CFBundleIdentifier
+ io.flutter.flutter.app
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ App
+ CFBundlePackageType
+ FMWK
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1.0
+ MinimumOSVersion
+ 9.0
+
+
diff --git a/view/flutter/demo_null_safety/ios/Flutter/Debug.xcconfig b/view/flutter/demo_null_safety/ios/Flutter/Debug.xcconfig
new file mode 100644
index 0000000000000000000000000000000000000000..592ceee85b89bd111b779db6116b130509ab6d4b
--- /dev/null
+++ b/view/flutter/demo_null_safety/ios/Flutter/Debug.xcconfig
@@ -0,0 +1 @@
+#include "Generated.xcconfig"
diff --git a/view/flutter/demo_null_safety/ios/Flutter/Release.xcconfig b/view/flutter/demo_null_safety/ios/Flutter/Release.xcconfig
new file mode 100644
index 0000000000000000000000000000000000000000..592ceee85b89bd111b779db6116b130509ab6d4b
--- /dev/null
+++ b/view/flutter/demo_null_safety/ios/Flutter/Release.xcconfig
@@ -0,0 +1 @@
+#include "Generated.xcconfig"
diff --git a/view/flutter/demo_null_safety/ios/Runner.xcodeproj/project.pbxproj b/view/flutter/demo_null_safety/ios/Runner.xcodeproj/project.pbxproj
new file mode 100644
index 0000000000000000000000000000000000000000..d63af51b714e5bee96a8e9bdd11641c951c2218b
--- /dev/null
+++ b/view/flutter/demo_null_safety/ios/Runner.xcodeproj/project.pbxproj
@@ -0,0 +1,503 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 50;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
+ 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
+ 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
+ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
+ 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
+ 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "";
+ dstSubfolderSpec = 10;
+ files = (
+ );
+ name = "Embed Frameworks";
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
+ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
+ 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
+ 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
+ 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
+ 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
+ 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
+ 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
+ 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
+ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
+ 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
+ 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 97C146EB1CF9000F007C117D /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 9740EEB11CF90186004384FC /* Flutter */ = {
+ isa = PBXGroup;
+ children = (
+ 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
+ 9740EEB21CF90195004384FC /* Debug.xcconfig */,
+ 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
+ 9740EEB31CF90195004384FC /* Generated.xcconfig */,
+ );
+ name = Flutter;
+ sourceTree = "";
+ };
+ 97C146E51CF9000F007C117D = {
+ isa = PBXGroup;
+ children = (
+ 9740EEB11CF90186004384FC /* Flutter */,
+ 97C146F01CF9000F007C117D /* Runner */,
+ 97C146EF1CF9000F007C117D /* Products */,
+ );
+ sourceTree = "";
+ };
+ 97C146EF1CF9000F007C117D /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 97C146EE1CF9000F007C117D /* Runner.app */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ 97C146F01CF9000F007C117D /* Runner */ = {
+ isa = PBXGroup;
+ children = (
+ 97C146FA1CF9000F007C117D /* Main.storyboard */,
+ 97C146FD1CF9000F007C117D /* Assets.xcassets */,
+ 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
+ 97C147021CF9000F007C117D /* Info.plist */,
+ 97C146F11CF9000F007C117D /* Supporting Files */,
+ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
+ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
+ 74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
+ 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
+ );
+ path = Runner;
+ sourceTree = "";
+ };
+ 97C146F11CF9000F007C117D /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ );
+ name = "Supporting Files";
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 97C146ED1CF9000F007C117D /* Runner */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
+ buildPhases = (
+ 9740EEB61CF901F6004384FC /* Run Script */,
+ 97C146EA1CF9000F007C117D /* Sources */,
+ 97C146EB1CF9000F007C117D /* Frameworks */,
+ 97C146EC1CF9000F007C117D /* Resources */,
+ 9705A1C41CF9048500538489 /* Embed Frameworks */,
+ 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = Runner;
+ productName = Runner;
+ productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 97C146E61CF9000F007C117D /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 1300;
+ ORGANIZATIONNAME = "The Chromium Authors";
+ TargetAttributes = {
+ 97C146ED1CF9000F007C117D = {
+ CreatedOnToolsVersion = 7.3.1;
+ LastSwiftMigration = 1100;
+ };
+ };
+ };
+ buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = en;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = 97C146E51CF9000F007C117D;
+ productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 97C146ED1CF9000F007C117D /* Runner */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 97C146EC1CF9000F007C117D /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
+ 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
+ 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
+ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Thin Binary";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
+ };
+ 9740EEB61CF901F6004384FC /* Run Script */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Run Script";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 97C146EA1CF9000F007C117D /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
+ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+ 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 97C146FB1CF9000F007C117D /* Base */,
+ );
+ name = Main.storyboard;
+ sourceTree = "";
+ };
+ 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 97C147001CF9000F007C117D /* Base */,
+ );
+ name = LaunchScreen.storyboard;
+ sourceTree = "";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 249021D3217E4FDB00AE95B9 /* Profile */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ SUPPORTED_PLATFORMS = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Profile;
+ };
+ 249021D4217E4FDB00AE95B9 /* Profile */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ ENABLE_BITCODE = NO;
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(PROJECT_DIR)/Flutter",
+ );
+ INFOPLIST_FILE = Runner/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(PROJECT_DIR)/Flutter",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = com.anjiplus.captcha;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+ SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Profile;
+ };
+ 97C147031CF9000F007C117D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ 97C147041CF9000F007C117D /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ SUPPORTED_PLATFORMS = iphoneos;
+ SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ 97C147061CF9000F007C117D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ ENABLE_BITCODE = NO;
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(PROJECT_DIR)/Flutter",
+ );
+ INFOPLIST_FILE = Runner/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(PROJECT_DIR)/Flutter",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = com.anjiplus.captcha;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Debug;
+ };
+ 97C147071CF9000F007C117D /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ ENABLE_BITCODE = NO;
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(PROJECT_DIR)/Flutter",
+ );
+ INFOPLIST_FILE = Runner/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(PROJECT_DIR)/Flutter",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = com.anjiplus.captcha;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+ SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 97C147031CF9000F007C117D /* Debug */,
+ 97C147041CF9000F007C117D /* Release */,
+ 249021D3217E4FDB00AE95B9 /* Profile */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 97C147061CF9000F007C117D /* Debug */,
+ 97C147071CF9000F007C117D /* Release */,
+ 249021D4217E4FDB00AE95B9 /* Profile */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 97C146E61CF9000F007C117D /* Project object */;
+}
diff --git a/view/flutter/demo_null_safety/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/view/flutter/demo_null_safety/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000000000000000000000000000000000000..919434a6254f0e9651f402737811be6634a03e9c
--- /dev/null
+++ b/view/flutter/demo_null_safety/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/view/flutter/demo_null_safety/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/view/flutter/demo_null_safety/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
new file mode 100644
index 0000000000000000000000000000000000000000..3db53b6e1fb7f8a5fae6c2e6eb4e3b4382a3691e
--- /dev/null
+++ b/view/flutter/demo_null_safety/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/view/flutter/demo_null_safety/ios/Runner.xcworkspace/contents.xcworkspacedata b/view/flutter/demo_null_safety/ios/Runner.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000000000000000000000000000000000000..1d526a16ed0f1cd0c2409d848bf489b93fefa3b2
--- /dev/null
+++ b/view/flutter/demo_null_safety/ios/Runner.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/view/flutter/demo_null_safety/ios/Runner/AppDelegate.swift b/view/flutter/demo_null_safety/ios/Runner/AppDelegate.swift
new file mode 100644
index 0000000000000000000000000000000000000000..70693e4a8c128fc4350b157416374ca599ac8c7b
--- /dev/null
+++ b/view/flutter/demo_null_safety/ios/Runner/AppDelegate.swift
@@ -0,0 +1,13 @@
+import UIKit
+import Flutter
+
+@UIApplicationMain
+@objc class AppDelegate: FlutterAppDelegate {
+ override func application(
+ _ application: UIApplication,
+ didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
+ ) -> Bool {
+ GeneratedPluginRegistrant.register(with: self)
+ return super.application(application, didFinishLaunchingWithOptions: launchOptions)
+ }
+}
diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000000000000000000000000000000000000..d36b1fab2d9dea668a4f83df94d525897d9e68dd
--- /dev/null
+++ b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,122 @@
+{
+ "images" : [
+ {
+ "size" : "20x20",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-20x20@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "20x20",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-20x20@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-29x29@1x.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-29x29@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-29x29@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-40x40@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-40x40@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-60x60@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "Icon-App-60x60@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "20x20",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-20x20@1x.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "20x20",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-20x20@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-29x29@1x.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-29x29@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-40x40@1x.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-40x40@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "76x76",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-76x76@1x.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "76x76",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-76x76@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "83.5x83.5",
+ "idiom" : "ipad",
+ "filename" : "Icon-App-83.5x83.5@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "1024x1024",
+ "idiom" : "ios-marketing",
+ "filename" : "Icon-App-1024x1024@1x.png",
+ "scale" : "1x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
new file mode 100644
index 0000000000000000000000000000000000000000..dc9ada4725e9b0ddb1deab583e5b5102493aa332
Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ
diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
new file mode 100644
index 0000000000000000000000000000000000000000..28c6bf03016f6c994b70f38d1b7346e5831b531f
Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ
diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..2ccbfd967d9697cd4b83225558af2911e9571c9b
Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ
diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
new file mode 100644
index 0000000000000000000000000000000000000000..f091b6b0bca859a3f474b03065bef75ba58a9e4c
Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ
diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
new file mode 100644
index 0000000000000000000000000000000000000000..4cde12118dda48d71e01fcb589a74d069c5d7cb5
Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ
diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..d0ef06e7edb86cdfe0d15b4b0d98334a86163658
Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ
diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
new file mode 100644
index 0000000000000000000000000000000000000000..dcdc2306c28505ebc0b6c3a359c4d252bf626b9f
Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ
diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
new file mode 100644
index 0000000000000000000000000000000000000000..2ccbfd967d9697cd4b83225558af2911e9571c9b
Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ
diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..c8f9ed8f5cee1c98386d13b17e89f719e83555b2
Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ
diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
new file mode 100644
index 0000000000000000000000000000000000000000..a6d6b8609df07bf62e5100a53a01510388bd2b22
Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ
diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..a6d6b8609df07bf62e5100a53a01510388bd2b22
Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ
diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
new file mode 100644
index 0000000000000000000000000000000000000000..75b2d164a5a98e212cca15ea7bf2ab5de5108680
Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ
diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
new file mode 100644
index 0000000000000000000000000000000000000000..c4df70d39da7941ef3f6dcb7f06a192d8dcb308d
Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ
diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..6a84f41e14e27f4b11f16f9ee39279ac98f8d5ac
Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ
diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..d0e1f58536026aebc4f1f70e481f6993c9ff088d
Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ
diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
new file mode 100644
index 0000000000000000000000000000000000000000..0bedcf2fd46788ae3a01a423467513ff59b5c120
--- /dev/null
+++ b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "LaunchImage.png",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "filename" : "LaunchImage@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "filename" : "LaunchImage@3x.png",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
new file mode 100644
index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838
Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ
diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838
Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ
diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
new file mode 100644
index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838
Binary files /dev/null and b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ
diff --git a/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..89c2725b70f1882be97f5214fafe22d27a0ec01e
--- /dev/null
+++ b/view/flutter/demo_null_safety/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
@@ -0,0 +1,5 @@
+# Launch Screen Assets
+
+You can customize the launch screen with your own desired assets by replacing the image files in this directory.
+
+You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
\ No newline at end of file
diff --git a/view/flutter/demo_null_safety/ios/Runner/Base.lproj/LaunchScreen.storyboard b/view/flutter/demo_null_safety/ios/Runner/Base.lproj/LaunchScreen.storyboard
new file mode 100644
index 0000000000000000000000000000000000000000..f2e259c7c9390ff69a6bbe1e0907e6dc366848e7
--- /dev/null
+++ b/view/flutter/demo_null_safety/ios/Runner/Base.lproj/LaunchScreen.storyboard
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/view/flutter/demo_null_safety/ios/Runner/Base.lproj/Main.storyboard b/view/flutter/demo_null_safety/ios/Runner/Base.lproj/Main.storyboard
new file mode 100644
index 0000000000000000000000000000000000000000..f3c28516fb38e64d88cfcf5fb1791175df078f2f
--- /dev/null
+++ b/view/flutter/demo_null_safety/ios/Runner/Base.lproj/Main.storyboard
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/view/flutter/demo_null_safety/ios/Runner/Info.plist b/view/flutter/demo_null_safety/ios/Runner/Info.plist
new file mode 100644
index 0000000000000000000000000000000000000000..88f1f9f56be876547f088fd75f13cab9a72a7edf
--- /dev/null
+++ b/view/flutter/demo_null_safety/ios/Runner/Info.plist
@@ -0,0 +1,47 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ captcha
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ $(FLUTTER_BUILD_NAME)
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ $(FLUTTER_BUILD_NUMBER)
+ LSRequiresIPhoneOS
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIMainStoryboardFile
+ Main
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UIViewControllerBasedStatusBarAppearance
+
+ CADisableMinimumFrameDurationOnPhone
+
+
+
diff --git a/view/flutter/demo_null_safety/ios/Runner/Runner-Bridging-Header.h b/view/flutter/demo_null_safety/ios/Runner/Runner-Bridging-Header.h
new file mode 100644
index 0000000000000000000000000000000000000000..7335fdf9000cec1b6c1e3f506b196734e8a427ff
--- /dev/null
+++ b/view/flutter/demo_null_safety/ios/Runner/Runner-Bridging-Header.h
@@ -0,0 +1 @@
+#import "GeneratedPluginRegistrant.h"
\ No newline at end of file
diff --git a/view/flutter/demo_null_safety/lib/captcha/block_puzzle_captcha.dart b/view/flutter/demo_null_safety/lib/captcha/block_puzzle_captcha.dart
new file mode 100644
index 0000000000000000000000000000000000000000..1aececc2d0755ea6f3fc35fcd241b13e9bb4d045
--- /dev/null
+++ b/view/flutter/demo_null_safety/lib/captcha/block_puzzle_captcha.dart
@@ -0,0 +1,545 @@
+import 'dart:convert';
+import 'dart:math';
+
+import 'package:captcha/request/HttpManager.dart';
+import 'package:captcha/request/encrypt_util.dart';
+import 'package:captcha/tools/object_utils.dart';
+import 'package:captcha/tools/widget_util.dart';
+import 'package:flutter/material.dart';
+import 'package:steel_crypt/steel_crypt.dart';
+typedef VoidSuccessCallback = dynamic Function(String v);
+class BlockPuzzleCaptchaPage extends StatefulWidget {
+ final VoidSuccessCallback? onSuccess; //拖放完成后验证成功回调
+ final VoidCallback? onFail; //拖放完成后验证失败回调
+
+ BlockPuzzleCaptchaPage({this.onSuccess, this.onFail});
+
+ @override
+ _BlockPuzzleCaptchaPageState createState() => _BlockPuzzleCaptchaPageState();
+}
+
+class _BlockPuzzleCaptchaPageState extends State
+ with TickerProviderStateMixin {
+// String baseImageBase64 =
+// "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";
+ String baseImageBase64 = "";
+ String slideImageBase64 = "";
+ String captchaToken = "";
+ String secretKey = "";//加密key
+
+ Size baseSize = Size.zero; //底部基类图片
+ Size slideSize = Size.zero; //滑块图片
+
+
+ var sliderColor = Colors.white; //滑块的背景色
+ var sliderIcon = Icons.arrow_forward; //滑块的图标
+ var movedXBorderColor = Colors.white; //滑块拖动时,左边已滑的区域边框颜色
+ double sliderStartX = 0; //滑块未拖前的X坐标
+ double sliderXMoved = 0;
+ bool sliderMoveFinish = false; //滑块拖动结束
+ bool checkResultAfterDrag = false; //拖动后的校验结果
+
+ //-------------动画------------
+ int _checkMilliseconds = 0; //滑动时间
+ bool _showTimeLine = false; //是否显示动画部件
+ bool _checkSuccess = false; //校验是否成功
+ late AnimationController controller;
+
+ //高度动画
+ late Animation offsetAnimation;
+
+ //底部部件key
+ GlobalKey _containerKey = new GlobalKey();
+ //背景图key
+ GlobalKey _baseImageKey = new GlobalKey();
+ //滑块
+ GlobalKey _slideImageKey = new GlobalKey();
+ double _bottomSliderSize = 60;
+
+
+ //------------动画------------
+
+ //校验通过
+ void checkSuccess(String content) {
+ setState(() {
+ checkResultAfterDrag = true;
+ _checkSuccess = true;
+ _showTimeLine = true;
+ });
+ _forwardAnimation();
+ updateSliderColorIcon();
+
+ //刷新验证码
+ Future.delayed(Duration(milliseconds: 1000)).then((v) {
+ _reverseAnimation().then((v) {
+ setState(() {
+ _showTimeLine = false;
+ });
+ //回调
+ if (widget.onSuccess != null) {
+ widget.onSuccess!(content);
+ }
+ //关闭验证码
+ print(content);
+ Navigator.pop(context);
+ });
+ });
+ }
+
+ //校验失败
+ void checkFail() {
+ setState(() {
+ _showTimeLine = true;
+ _checkSuccess = false;
+ checkResultAfterDrag = false;
+ });
+ _forwardAnimation();
+ updateSliderColorIcon();
+
+ //刷新验证码
+ Future.delayed(Duration(milliseconds: 1000)).then((v) {
+ _reverseAnimation().then((v) {
+ setState(() {
+ _showTimeLine = false;
+ });
+ loadCaptcha();
+ //回调
+ if (widget.onFail != null) {
+ widget.onFail!();
+ }
+ });
+ });
+ }
+
+ //重设滑动颜色与图标
+ void updateSliderColorIcon() {
+ var _sliderColor; //滑块的背景色
+ var _sliderIcon; //滑块的图标
+ var _movedXBorderColor; //滑块拖动时,左边已滑的区域边框颜色
+
+ //滑块的背景色
+ if (sliderMoveFinish) {
+ //拖动结束
+ _sliderColor = checkResultAfterDrag ? Colors.green : Colors.red;
+ _sliderIcon = checkResultAfterDrag ? Icons.check : Icons.close;
+ _movedXBorderColor = checkResultAfterDrag ? Colors.green : Colors.red;
+ } else {
+ //拖动未开始或正在拖动中
+ _sliderColor = sliderXMoved > 0 ? Color(0xff447ab2) : Colors.white;
+ _sliderIcon = Icons.arrow_forward;
+ _movedXBorderColor = Color(0xff447ab2);
+ }
+
+ sliderColor = _sliderColor;
+ sliderIcon = _sliderIcon;
+ movedXBorderColor = _movedXBorderColor;
+ setState(() {});
+ }
+
+ //加载验证码
+ void loadCaptcha() {
+ setState(() {
+ _showTimeLine = false;
+ sliderMoveFinish = false;
+ checkResultAfterDrag = false;
+ sliderColor = Colors.white; //滑块的背景色
+ sliderIcon = Icons.arrow_forward; //滑块的图标
+ movedXBorderColor = Colors.white; //滑块拖动时,左边已滑的区域边框颜色
+ });
+ HttpManager.requestData(
+ '/captcha/get', {"captchaType": "blockPuzzle"}, {})
+ .then((res) async {
+ if (res['repCode'] != '0000' || res['repData'] == null) {
+ setState(() {
+ secretKey = "";
+ });
+ return;
+ }
+
+ Map repData = res['repData'];
+ sliderXMoved = 0;
+ sliderStartX = 0;
+ captchaToken = '';
+ checkResultAfterDrag = false;
+
+ baseImageBase64 = repData["originalImageBase64"];
+ baseImageBase64 = repData["originalImageBase64"];
+ secretKey = repData["secretKey"] ?? "";
+ baseImageBase64 = baseImageBase64.replaceAll('\n', '');
+ slideImageBase64 = repData["jigsawImageBase64"];
+ slideImageBase64 = slideImageBase64.replaceAll('\n', '');
+ captchaToken = repData["token"];
+
+ var baseR = await WidgetUtil.getImageWH(
+ image: Image.memory(Base64Decoder().convert(baseImageBase64)));
+ baseSize = baseR.size;
+
+ var silderR = await WidgetUtil.getImageWH(
+ image: Image.memory(Base64Decoder().convert(slideImageBase64)));
+ slideSize = silderR.size;
+
+ setState(() {});
+ }).catchError((error) {
+ print(error);
+ });
+ }
+
+ //校验验证码
+ void checkCaptcha(sliderXMoved, captchaToken, {BuildContext? myContext}) {
+ setState(() {
+ sliderMoveFinish = true;
+ });
+ //滑动结束,改变滑块的图标及颜色
+// updateSliderColorIcon();
+
+ //pointJson参数需要aes加密
+
+// MediaQueryData mediaQuery = MediaQuery.of(myContext);
+ var pointMap = {"x": sliderXMoved, "y": 5};
+ var pointStr = json.encode(pointMap);
+ var cryptedStr = pointStr;
+
+ // secretKey 不为空 进行as加密
+ if(!ObjectUtils.isEmpty(secretKey)){
+ cryptedStr = EncryptUtil.aesEncode(key: secretKey, content: pointStr);
+ var dcrypt = EncryptUtil.aesDecode(key: secretKey, content: cryptedStr);
+ json.decode(dcrypt);
+
+ }
+
+
+ HttpManager.requestData('/captcha/check', {
+ "pointJson": cryptedStr,
+ "captchaType": "blockPuzzle",
+ "token": captchaToken
+ }, {}).then((res) {
+ if (res['repCode'] != '0000' || res['repData'] == null) {
+ checkFail();
+ return;
+ }
+
+ Map repData = res['repData'];
+ if (repData["result"] != null && repData["result"] == true) {
+ //如果不加密 将 token 和 坐标序列化 通过 --- 链接成字符串
+ var captchaVerification = "$captchaToken---$pointStr";
+ if(!ObjectUtils.isEmpty(secretKey)){
+ //如果加密 将 token 和 坐标序列化 通过 --- 链接成字符串 进行加密 加密密钥为 _clickWordCaptchaModel.secretKey
+ captchaVerification = EncryptUtil.aesEncode(key: secretKey, content: captchaVerification);
+ }
+ checkSuccess(captchaVerification);
+ } else {
+ checkFail();
+ }
+ }).catchError((error) {
+ loadCaptcha();
+ print(error);
+ });
+ }
+
+ @override
+ void initState() {
+ super.initState();
+ initAnimation();
+ loadCaptcha();
+ }
+
+ @override
+ void dispose() {
+ controller.dispose();
+ super.dispose();
+ }
+
+ // 初始化动画
+ void initAnimation() {
+ controller =
+ AnimationController(duration: Duration(milliseconds: 500), vsync: this);
+
+ offsetAnimation = Tween(begin: 0.5, end: 0)
+ .animate(CurvedAnimation(parent: controller, curve: Curves.ease))
+ ..addListener(() {
+ this.setState(() {});
+ });
+ }
+
+ // 反向执行动画
+ _reverseAnimation() async {
+ await controller.reverse();
+ }
+
+ // 正向执行动画
+ _forwardAnimation() async {
+ await controller.forward();
+ }
+
+ @override
+ void didUpdateWidget(BlockPuzzleCaptchaPage oldWidget) {
+ // TODO: implement didUpdateWidget
+ super.didUpdateWidget(oldWidget);
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return MaxScaleTextWidget(
+ child: buildContent(context),
+ );
+ }
+
+ Widget buildContent(BuildContext context) {
+ var mediaQuery = MediaQuery.of(context);
+ var dialogWidth = 0.9 * mediaQuery.size.width;
+ if (dialogWidth < 330) {
+ dialogWidth = mediaQuery.size.width;
+ }
+
+ return Scaffold(
+ backgroundColor: Colors.transparent,
+ body: Center(
+ child: Container(
+ key: _containerKey,
+ width: dialogWidth,
+ height: 340,
+ color: Colors.white,
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.start,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ _topContainer(),
+ _middleContainer(),
+ _bottomContainer(),
+ ],
+ ),
+ ),
+ ),
+ );
+ }
+
+ ///顶部,提示+关闭
+ _topContainer() {
+ return Container(
+ height: 50,
+ padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ decoration: BoxDecoration(
+ border: Border(bottom: BorderSide(width: 1, color: Color(0xffe5e5e5))),
+ ),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Text(
+ '请完成安全验证',
+ style: TextStyle(fontSize: 18),
+ ),
+ IconButton(
+ icon: Icon(Icons.highlight_off),
+ iconSize: 30,
+ color: Colors.black38,
+ onPressed: () {
+ //退出
+ Navigator.pop(context);
+ }),
+ ],
+ ),
+ );
+ }
+
+ _middleContainer() {
+ ////显示验证码
+ return Container(
+ margin: EdgeInsets.symmetric(vertical: 10),
+ child: Stack(
+ children: [
+ ///底图 310*155
+ baseImageBase64.length > 0
+ ? Image.memory(
+ Base64Decoder().convert(baseImageBase64),
+ fit: BoxFit.fitWidth,
+ key: _baseImageKey,
+ gaplessPlayback: true,
+ )
+ : Container(
+ width: 310,
+ height: 155,
+ alignment: Alignment.center,
+ child: CircularProgressIndicator(),
+ ),
+
+ ///滑块图
+ slideImageBase64.length > 0
+ ? Container(
+ margin: EdgeInsets.fromLTRB(sliderXMoved, 0, 0, 0),
+ child: Image.memory(
+ Base64Decoder().convert(slideImageBase64),
+ fit: BoxFit.fitHeight,
+ key: _slideImageKey,
+ gaplessPlayback: true,
+ ),
+ )
+ : Container(),
+
+ //刷新按钮
+ Positioned(
+ top: 0,
+ right: 0,
+ child: IconButton(
+ icon: Icon(Icons.refresh),
+ iconSize: 30,
+ color: Colors.black54,
+ onPressed: () {
+ //刷新
+ loadCaptcha();
+ }),
+ ),
+ Positioned(
+ bottom: 0,
+ left: -10,
+ right: -10,
+ child: Offstage(
+ offstage: !_showTimeLine,
+ child: FractionalTranslation(
+ translation: Offset(0, offsetAnimation.value),
+ child: Container(
+ margin: EdgeInsets.only(left: 10, right: 10),
+ height: 40,
+ color: _checkSuccess
+ ? Color(0x7F66BB6A)
+ : Color.fromRGBO(200, 100, 100, 0.4),
+ alignment: Alignment.centerLeft,
+ child: Text(
+ _checkSuccess
+ ? "${(_checkMilliseconds / (60.0 * 12)).toStringAsFixed(2)}s验证成功"
+ : "验证失败",
+ style: TextStyle(color: Colors.white),
+ ),
+ ),
+ ),
+ )),
+ Positioned(
+ bottom: -20,
+ left: 0,
+ right: 0,
+ child: Offstage(
+ offstage: !_showTimeLine,
+ child: Container(
+ margin: EdgeInsets.only(left: 10, right: 10),
+ height: 20,
+ color: Colors.white,
+ ),
+ ))
+ ],
+ ),
+ );
+ }
+ ///底部,滑动区域
+ _bottomContainer() {
+ return baseSize.width >0
+ ? Container(
+ height: 70,
+ width: baseSize.width,
+// color: Colors.cyanAccent,
+ child: Stack(
+ alignment: AlignmentDirectional.centerStart,
+ children: [
+ Container(
+ height: _bottomSliderSize,
+ decoration: BoxDecoration(
+ border: Border.all(
+ width: 1,
+ color: Color(0xffe5e5e5),
+ ),
+ color: Color(0xfff8f9fb),
+ ),
+ ),
+ Container(
+ alignment: Alignment.center,
+ child: Text(
+ '向右拖动滑块填充拼图',
+ style: TextStyle(fontSize: 16),
+ ),
+ ),
+ Container(
+ width: sliderXMoved,
+ height: _bottomSliderSize-2,
+ decoration: BoxDecoration(
+ border: Border.all(
+ width: sliderXMoved > 0 ? 1 : 0,
+ color: movedXBorderColor,
+ ),
+ color: Color(0xfff3fef1),
+ ),
+ ),
+ GestureDetector(
+ onPanStart: (startDetails) {///开始
+ _checkMilliseconds = new DateTime.now().millisecondsSinceEpoch;
+ print(startDetails.localPosition);
+ sliderStartX = startDetails.localPosition.dx;
+ },
+ onPanUpdate: (updateDetails) { ///更新
+ print(updateDetails.localPosition);
+ double _w1 = _baseImageKey.currentContext!.size!.width - _slideImageKey.currentContext!.size!.width;
+ double offset = updateDetails.localPosition.dx - sliderStartX;
+ if(offset < 0){
+ offset = 0;
+ }
+ if(offset > _w1){
+ offset = _w1;
+ }
+ print("offset ------ $offset");
+ setState(() {
+ sliderXMoved = offset;
+ });
+ //滑动过程,改变滑块左边框颜色
+ updateSliderColorIcon();
+ },
+ onPanEnd: (endDetails) { //结束
+ print("endDetails");
+ checkCaptcha(sliderXMoved, captchaToken);
+ int _nowTime = new DateTime.now().millisecondsSinceEpoch;
+ _checkMilliseconds = _nowTime - _checkMilliseconds;
+ },
+ child: Container(
+ width: _bottomSliderSize,
+ height: _bottomSliderSize,
+ margin: EdgeInsets.only(left: sliderXMoved > 0 ? sliderXMoved : 1),
+ decoration: BoxDecoration(
+ border: Border(
+ top: BorderSide(
+ width: 1,
+ color: Color(0xffe5e5e5),
+ ),
+ right: BorderSide(
+ width: 1,
+ color: Color(0xffe5e5e5),
+ ),
+ bottom: BorderSide(
+ width: 1,
+ color: Color(0xffe5e5e5),
+ ),
+ ),
+ color: sliderColor,
+ ),
+ child: IconButton(
+ icon: Icon(sliderIcon),
+ iconSize: 30,
+ color: Colors.black54, onPressed: () { },
+ ),
+ ),
+ )
+ ],
+ ))
+ : Container();
+ }
+}
+
+
+class MaxScaleTextWidget extends StatelessWidget {
+ final double max;
+ final Widget child;
+
+ MaxScaleTextWidget({Key? key, this.max = 1.0, required this.child}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ var data = MediaQuery.of(context);
+ var textScaleFactor = min(max, data.textScaleFactor);
+ return MediaQuery(data: data.copyWith(textScaleFactor: textScaleFactor), child: child);
+ }
+}
diff --git a/view/flutter/demo_null_safety/lib/captcha/click_word_captcha.dart b/view/flutter/demo_null_safety/lib/captcha/click_word_captcha.dart
new file mode 100644
index 0000000000000000000000000000000000000000..56e1f2e3572abd75d15c1e1547be358cf7d57af5
--- /dev/null
+++ b/view/flutter/demo_null_safety/lib/captcha/click_word_captcha.dart
@@ -0,0 +1,367 @@
+import 'dart:convert';
+
+import 'package:captcha/request/HttpManager.dart';
+import 'package:captcha/request/encrypt_util.dart';
+import 'package:captcha/tools/object_utils.dart';
+import 'package:captcha/tools/widget_util.dart';
+import 'package:flutter/material.dart';
+import 'package:steel_crypt/steel_crypt.dart';
+
+typedef VoidSuccessCallback = dynamic Function(String v);
+
+class ClickWordCaptcha extends StatefulWidget {
+ final VoidSuccessCallback? onSuccess; //文字点击后验证成功回调
+ final VoidCallback? onFail; //文字点击完成后验证失败回调
+
+ const ClickWordCaptcha({Key? key, this.onSuccess, this.onFail})
+ : super(key: key);
+
+ @override
+ _ClickWordCaptchaState createState() => _ClickWordCaptchaState();
+}
+
+class _ClickWordCaptchaState extends State {
+ ClickWordCaptchaState _clickWordCaptchaState = ClickWordCaptchaState.none;
+ List _tapOffsetList = [];
+ ClickWordCaptchaModel _clickWordCaptchaModel = ClickWordCaptchaModel();
+
+ Color titleColor = Colors.black;
+ Color borderColor = Color(0xffdddddd);
+ String bottomTitle = "";
+ Size baseSize = Size(310.0, 155.0);
+
+ //改变底部样式及字段
+ _changeResultState() {
+ switch (_clickWordCaptchaState) {
+ case ClickWordCaptchaState.normal:
+ titleColor = Colors.black;
+ borderColor = Color(0xffdddddd);
+ break;
+ case ClickWordCaptchaState.success:
+ _tapOffsetList = [];
+ titleColor = Colors.green;
+ borderColor = Colors.green;
+ bottomTitle = "验证成功";
+ break;
+ case ClickWordCaptchaState.fail:
+ _tapOffsetList = [];
+ titleColor = Colors.red;
+ borderColor = Colors.red;
+ bottomTitle = "验证失败";
+ break;
+ default:
+ titleColor = Colors.black;
+ borderColor = Color(0xffdddddd);
+ bottomTitle = "数据加载中……";
+ break;
+ }
+ setState(() {});
+ }
+
+ @override
+ void initState() {
+ super.initState();
+ _loadCaptcha();
+ }
+
+ //加载验证码
+ _loadCaptcha() async {
+ _tapOffsetList = [];
+ _clickWordCaptchaState = ClickWordCaptchaState.none;
+ _changeResultState();
+ var res = await HttpManager.requestData(
+ '/captcha/get', {"captchaType": "clickWord"}, {});
+ if (res['repCode'] != '0000' || res['repData'] == null) {
+ _clickWordCaptchaModel.secretKey = "";
+ bottomTitle = "加载失败,请刷新";
+ _clickWordCaptchaState = ClickWordCaptchaState.normal;
+ _changeResultState();
+ return;
+ } else {
+ Map repData = res['repData'];
+ _clickWordCaptchaModel = ClickWordCaptchaModel.fromMap(repData);
+
+ var baseR = await WidgetUtil.getImageWH(
+ image: Image.memory(
+ Base64Decoder().convert(_clickWordCaptchaModel.imgStr)));
+ baseSize = baseR.size;
+
+ bottomTitle = "请依次点击【${_clickWordCaptchaModel.wordStr}】";
+ }
+
+ _clickWordCaptchaState = ClickWordCaptchaState.normal;
+ _changeResultState();
+ }
+
+ //校验验证码
+ _checkCaptcha() async {
+ List