flutter go 项目下载后,运行报如下错误:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Launching lib/main.dart on iPhone Xʀ in debug mode...
Running Xcode build...

Xcode build done. 3.3s
Failed to build iOS app
Error output from Xcode build:

** BUILD FAILED **


Xcode's output:

=== BUILD TARGET firebase_analytics OF PROJECT Pods WITH CONFIGURATION Debug ===
/Users/l/Documents/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_analytics-2.1.1+2/ios/Classes/FirebaseAnalyticsPlu
gin.m:60:7: error: use of undeclared identifier 'FIRAnalyticsConfiguration'
[[FIRAnalyticsConfiguration sharedInstance] setAnalyticsCollectionEnabled:[enabled boolValue]];
^
1 error generated.

Could not build the application for the simulator.
Error launching application on iPhone Xʀ.

解决方案:


将根目录下pubspec.yaml文件中 firebase_analytics: ^2.0.2+1 改为 firebase_analytics: ^3.0.1 之后运行flutter run


执行通过

1. ‘Flutter/Flutter.h’ file not found

解决方案1.

点击这里前往下载对应版本文件,替换原来的文件ios/Podfile内容,删除ios/Podfile.lock,重新 pod install 即可

解决方案2.

执行代码:flutter run -vflutter doctor -v 检测配置是否成功

可能会出现以下情况:

Mac os 10.15 无法打开“idevice_id”,因为无法验证开发者

Mac os 10.15 无法打开“ideviceinfo”,因为无法验证开发者

解决方法 打开终端(Terminal),输入以下命令后回车,如需要,请输入密码

sudo xattr -r -d com.apple.quarantine <path>

注:为应用程序路径,直接从文件夹目录拖拽即可自动填写

解决方案3.

找到 iOS/Flutter 文件夹,再找到以前备份的无报错代码替换掉文件夹内容,应该就不会报错了。

再执行下 flutter build ios --release
编译过程中会重新生成新的 iOS/Flutter 文件夹下内容,覆盖我们替换的文件。

以上解决方案有可能需要结合使用。

1. ViewModelProviders

build.gradledependencies 中加入

1
implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'

在使用的地方导入:

1
import androidx.lifecycle.ViewModelProviders;

即可使用:

1
myViewModel = ViewModelProviders.of(this).get(MyViewModel.class);

该方法 2.1.0 已弃用 ViewModelProviders.of() ,改为

1
2
3
4
5
//导入 import androidx.lifecycle.ViewModelProvider;
myViewModel = ViewModelProvider(this).get(MyViewModel.class);

//或者
myViewModel = ViewModelProvider(getActivity()).get(MyViewModel.class);

2. DataBinding

build.gradle 的 defaultConfig中加入

1
2
3
dataBinding{
enabled true
}

Sync Now一下,把下面代码套在布局最外层,即可使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">

<data>

</data>


//============
//这里写自己的布局


</layout>

解决方案:

  1. 修改Flutter SDK中的flutter.gradle文件,通过 flutter>packages>flutter_tools>gradle>flutter.gradle(注意这是Flutter SDK安装位置不是Android Studio的)路径找到flutter.gradle,打开flutter.gradle文件,修改配置:

注释掉google()jcenter(),加入阿里的配置项

1
2
3
maven {url 'https://maven.aliyun.com/repository/google'}
maven {url 'https://maven.aliyun.com/repository/jcenter'}
maven {url 'https://maven.aliyun.com/nexus/content/groups/public'}

修改后:

1
2
3
4
5
6
7
8
9
10
11
12
13
buildscript {
repositories {
//注释掉 google()和jcenter()
// google()
// jcenter()
maven {url 'https://maven.aliyun.com/repository/google'}
maven {url 'https://maven.aliyun.com/repository/jcenter'}
maven {url 'https://maven.aliyun.com/nexus/content/groups/public'}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
}
}
  1. 手动下载gradle进行配置

    找到创建的flutter项目:

    通过路径flutterdemo001/android/gradle/wrapper/gradle-wrapper.properties找到对应文件打开后:

1
2
3
4
5
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-4.10.2-all.zip


找到distributionUrl对应的地址https://services.gradle.org/distributions/gradle-4.10.2-all.zip就是gradle的下载地址,注意文件中https后面有个\,复制到浏览器记得要删掉

点击下载 gradle-4.10.2-all.zip

点击下载其他版本gradle

下载完成后,进行解压。
然后打开目录:Macintosh HD 》 用户 》当前登录用户名称》.gradle》wrapper》dists⁩,
可能有些电脑未打开隐藏文件可见,是看不到.gradle文件夹的,它是一个隐藏文件夹。
使用快捷键shift+command+.来切换隐藏文件可见还是隐藏。找到dists文件夹后,把解压后的gradle拷贝一份放到dists文件夹下即可。

Swift 简单链表实现

链表中的元素在内存中不是顺序存储的,查找慢,插入、删除只需要对元素指针重新赋值,效率高;数组元素在内存上连续存放,可以通过下标查找元素;插入、删除需要移动大量元素,比较适用于元素很少变化的情况

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114

import UIKit

//链表节点
public class Node{

var value: T //节点存储数据
weak var next: Node? //节点链接到的下一个节点

weak var previous: Node?//节点链接到的上一个节点

init(value: T) {
self.value = value
}
}

//自定义链表
public class NodeList:CustomStringConvertible{
//链表起点节点
private var head:Node?

//链表终点节点
private var tail:Node?

//链表内数据是否为空
public var isEmpty:Bool{
return head == nil
}
//返回第一个节点
public var first:Node?{
return head
}
//返回最后一个节点
public var last:Node?{
return tail
}

//添加一个链接节点数据
public func append(value:T){
let newNode = Node(value: value)
if let tailNode = tail{
newNode.previous = tailNode
tailNode.next = newNode
}else{
head = newNode
}
tail = newNode
}

//删除节点
public func remove(node:Node) -> T{

//保存要删除节点的上一个和下一个节点
let prev = node.previous
let next = node.next

//如果要删处节点的上一节点不为空
if let prev = prev {
//上一个节点链接到的下一个节点,修改为要删除的下一个节点
prev.next = next
}
//如果要删处节点的上一节点为空,说明要删除的是链表起点节点
else {
//把下一个节点改为起点节点
head = next
}

//要删出的上一个节点,链接到上一个节点
next?.previous = prev
if next == nil {
//next为nil说明要删除的是最后一个,把倒数以前倒数第二个,置为最后一个
tail = prev
}

node.previous = nil
node.next = nil
return node.value

}
//删除所有节点数据
public func removeAll() {
head = nil
tail = nil
}

//取对应索引的节点
public func nodeAt(index: Int) -> Node? {
if index >= 0 {
var node = head
var i = index
while node != nil {
if i == 0 { return node }
i -= 1
node = node!.next
}
}
return nil
}

//输出节点数据
public var description: String{
var text = ""
var node = head
while node != nil {
text += "\(node!.value)"

node = node!.next
if node != nil {
text += ","
}
}
return "[" + text + "]"
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {

for touch:AnyObject in touches {
let t:UITouch = touch as! UITouch
//检测当前触摸的view是否是textField
if t.view == pwdField || t.view == pwdField || t.view == phoneField{
t.view?.becomeFirstResponder()
}else{
phoneField.resignFirstResponder()
pwdField.resignFirstResponder()
verificationField.resignFirstResponder()
self.resignFirstResponder()
}
}

}

通过响应者链获取对应的第一个符合条件的Responsder

传入响应检测的起点Responsder,一般用于UIView中查找响应者链中的控制器

1
2
3
4
5
6
7
func nextResponder(currentView:UIView)->UIViewController{
var vc:UIResponder = currentView
while vc.isKind(of: UIViewController.self) != true {
vc = vc.next!
}
return vc as! UIViewController
}

String->Class

Swift中引入了命名空间的概念,转Class需要拼接命名空间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

//这是一个简单的通过字符串类名,转Class然后初始化后跳转的一个小例子
@objc func OnClick(){

//控制器字符串名称
let vcNameString = "OneViewController"
//获取命名空间也就是项目名称
let clsName = Bundle.main.infoDictionary!["CFBundleExecutable"] as? String

//拼接
let className=clsName! + "." + vcNameString

//字符串转Class 需要注意的是这里的`UIViewController`强转必须带上`.Type`,否则转换不成功
let classT = NSClassFromString(className)! as! UIViewController.Type


URLRouter.shared.pushViewController(viewController:classT.init() , animated: true)
}//成功完成跳转