0%

早上开车等红绿灯时想到几个月前写的一个算法,应该可以更简单,今天重新写了一遍

  • 寻找下一个数字,例如输入345,输出354

    思路:从最右边位和上一位对比,如果大,就往前移,移动完,尾数排序,从小到大,保证次大

  • 代码

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
//字符串分成数组
NSMutableArray *convertStringToArray(NSString *str){
NSMutableArray *marr = [NSMutableArray array];
for (NSInteger i = 0; i < str.length; i++) {
[marr addObject:[str substringWithRange:NSMakeRange(i, 1)]];
}
return marr;
}

//数组拼成字符串
NSString *convertArrayToString(NSArray *arr){
NSMutableString *mstr = [NSMutableString string];
for (NSString *str in arr) {
[mstr appendString:str];
}
return mstr;
}

//冒泡排序 从小到大
NSString *bubbleSort(NSString *str){
NSArray *sortedArray = convertStringToArray(str);
NSMutableArray *marr = [NSMutableArray arrayWithArray:sortedArray];
//最后一位的索引
unsigned long j = marr.count-1;
for (;j>0;j--) {

BOOL didSort = NO;
//第一轮结束
for (int i=0; i<j; i++) {
NSString *pre = marr[i];
NSString *next = marr[i+1];
if (pre.integerValue > next.integerValue) {
[marr exchangeObjectAtIndex:i+1 withObjectAtIndex:i];
didSort = YES;
}
}

if (!didSort) {
break;
}
}

NSMutableString *mstr = [NSMutableString string];
for (NSString *str in marr) {
[mstr appendString:str];
}
return mstr;

}


NSString *findNextLargerNum(NSString *oriNum){
NSString *resultStr = oriNum;
NSMutableArray *oriNumMArr =[NSMutableArray arrayWithArray:convertStringToArray(oriNum)];

for (int j = oriNumMArr.count-1; j>0; j--) {

BOOL getResult = NO;
NSString *last = oriNumMArr[j];
for (int i = j-1; i>=0; i--) {
NSString *pre = oriNumMArr[i];
if (last.integerValue > pre.integerValue) {
[oriNumMArr exchangeObjectAtIndex:i withObjectAtIndex:j];
NSRange range = NSMakeRange(i+1, oriNumMArr.count - 1 - i);
NSString *surfixStr = convertArrayToString([oriNumMArr subarrayWithRange:range]);
NSString *surResultStr = bubbleSort(surfixStr);
NSString *preStr = convertArrayToString([oriNumMArr subarrayWithRange:NSMakeRange(0,i+1)]);
resultStr = [NSString stringWithFormat:@"%@%@",preStr,surResultStr];
getResult = YES;
break;
}
}


if (getResult) {
break;
}

}
return resultStr;
}
使用:
1
2
3
4
NSString *str = findNextLargerNum(@"8976");
NSLog(@"======%@",str);
//打印结果
======9678

  • 抽取widget,尽量成为一个stateless widget

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    class MainWidget extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
    return Expanded(
    child: Container(
    color: Colors.grey[700],
    child: Center(
    child: Text(
    'Hello Flutter',
    style: Theme.of(context).textTheme.display1,
    ),
    ),
    ),
    );
    }
    }
  • 更新属性值,用传值的方式

    • ChangeNotifier

      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
      //------ ChangeNotifier class ----//
      class MyColorNotifier extends ChangeNotifier {
      Color myColor = Colors.grey;
      Random _random = new Random();

      void changeColor() {
      int randomNumber = _random.nextInt(30);
      myColor = Colors.primaries[randomNumber % Colors.primaries.length];
      notifyListeners();
      }
      }
      //------ State class ----//

      class _MyHomePageState extends State<MyHomePage> {
      final _colorNotifier = MyColorNotifier();

      void _onPressed() {
      _colorNotifier.changeColor();
      }

      @override
      void dispose() {
      _colorNotifier.dispose();
      super.dispose();
      }

      @override
      Widget build(BuildContext context) {
      print('building `MyHomePage`');
      return Scaffold(
      floatingActionButton: FloatingActionButton(
      onPressed: _onPressed,
      child: Icon(Icons.colorize),
      ),
      body: Stack(
      children: [
      Positioned.fill(
      child: BackgroundWidget(),
      ),
      Center(
      child: AnimatedBuilder(
      animation: _colorNotifier,
      builder: (_, __) => Container(
      height: 150,
      width: 150,
      color: _colorNotifier.myColor,
      ),
      ),
      ),
      ],
      ),
      );
      }
      }
  • ValueNotifier

    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
    class _MyHomePageState extends State<MyHomePage> {
    final _colorNotifier = ValueNotifier<Color>(Colors.grey);
    Random _random = new Random();

    void _onPressed() {
    int randomNumber = _random.nextInt(30);
    _colorNotifier.value =
    Colors.primaries[randomNumber % Colors.primaries.length];
    }

    @override
    void dispose() {
    _colorNotifier.dispose();
    super.dispose();
    }

    @override
    Widget build(BuildContext context) {
    print('building `MyHomePage`');
    return Scaffold(
    floatingActionButton: FloatingActionButton(
    onPressed: _onPressed,
    child: Icon(Icons.colorize),
    ),
    body: Stack(
    children: [
    Positioned.fill(
    child: BackgroundWidget(),
    ),
    Center(
    child: ValueListenableBuilder(
    valueListenable: _colorNotifier,
    builder: (_, value, __) => Container(
    height: 150,
    width: 150,
    color: value,
    ),
    ),
    ),
    ],
    ),
    );
    }
    }
  • 使用const修饰stateless widget,set state不会重复刷新

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class BackgroundWidget extends StatelessWidget {
    const BackgroundWidget();

    @override
    Widget build(BuildContext context) {
    print('building `BackgroundWidget`');
    return Image.network(
    'https://cdn.pixabay.com/photo/2017/08/30/01/05/milky-way-2695569_960_720.jpg',
    fit: BoxFit.cover,
    );
    }
    }
  • 生成列表的时候使用itemExtent属性告诉系统item高度,更高效的滑动

    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
    class MyHomePage extends StatelessWidget {
    final widgets = List.generate(
    10000,
    (index) => Container(
    color: Colors.primaries[index % Colors.primaries.length],
    child: ListTile(
    title: Text('Index: $index'),
    ),
    ),
    );

    final _scrollController = ScrollController();

    void _onPressed() async {
    _scrollController.jumpTo(
    _scrollController.position.maxScrollExtent,
    );
    }

    @override
    Widget build(BuildContext context) {
    return Scaffold(
    floatingActionButton: FloatingActionButton(
    onPressed: _onPressed,
    splashColor: Colors.red,
    child: Icon(Icons.slow_motion_video),
    ),
    body: ListView(
    controller: _scrollController,
    children: widgets,
    itemExtent: 200,
    ),
    );
    }
    }
  • 需要动画的子控件设置给AnimatedBuilder的child,避免重复绘制

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    @override
    Widget build(BuildContext context) {
    return Scaffold(
    floatingActionButton: FloatingActionButton(
    onPressed: _onPressed,
    splashColor: Colors.red,
    child: Icon(Icons.slow_motion_video),
    ),
    body: AnimatedBuilder(
    animation: _controller,
    child: CounterWidget(
    counter: counter,
    ),
    builder: (_, child) => Transform(
    alignment: Alignment.center,
    transform: Matrix4.identity()
    ..setEntry(3, 2, 0.001)
    ..rotateY(360 * _controller.value * (pi / 180.0)),
    child: child,
    ),
    ),
    );
    }
  • 合理使用opacity属性,减少调用setlayer方法,触发离屏渲染

    • 使用fadeTransition

      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
      class _MyHomePageState extends State<MyHomePage>
      with SingleTickerProviderStateMixin {
      AnimationController _controller;
      int counter = 0;

      void _onPressed() {
      setState(() {
      counter++;
      });
      _controller.forward(from: 0.0);
      }

      @override
      void initState() {
      _controller = AnimationController(
      vsync: this, duration: const Duration(milliseconds: 600));
      _controller.addStatusListener((status) {
      if (status == AnimationStatus.completed) {
      _controller.reverse();
      }
      });
      super.initState();
      }

      @override
      void dispose() {
      _controller.dispose();
      super.dispose();
      }

      @override
      Widget build(BuildContext context) {
      return Scaffold(
      floatingActionButton: FloatingActionButton(
      onPressed: _onPressed,
      splashColor: Colors.red,
      child: Icon(Icons.slow_motion_video),
      ),
      body: FadeTransition(
      opacity: Tween(begin: 1.0, end: 0.0).animate(_controller),
      child: CounterWidget(
      counter: counter,
      ),
      ),
      );
      }
      }
  • 使用animatedOpacity

    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
    const duration = const Duration(milliseconds: 600);

    class _MyHomePageState extends State<MyHomePage> {
    int counter = 0;
    double opacity = 1.0;

    void _onPressed() async {
    counter++;
    setState(() {
    opacity = 0.0;
    });
    await Future.delayed(duration);
    setState(() {
    opacity = 1.0;
    });
    }

    @override
    Widget build(BuildContext context) {
    return Scaffold(
    floatingActionButton: FloatingActionButton(
    onPressed: _onPressed,
    splashColor: Colors.red,
    child: Icon(Icons.slow_motion_video),
    ),
    body: AnimatedOpacity(
    opacity: opacity,
    duration: duration,
    child: CounterWidget(
    counter: counter,
    ),
    ),
    );
    }
    }

完。

sources:

问题描述:

flutter工程打包apk文件后

1
2
3
4
5
6
7
8
9
10
try {
val method = javaClass.getDeclaredMethod(call.method, MethodCall::class.java, MethodChannel.Result::class.java)
method.invoke(this, call, result)
} catch (e: NoSuchMethodException) {
e.printStackTrace()
} catch (e: IllegalAccessException) {
e.printStackTrace()
} catch (e: InvocationTargetException) {
e.printStackTrace()
}

这段代码无法执行

原因分析

经过咨询,安卓release包会代码混淆,使用反射会让代码无法精确匹配

解决:

  • 使用反射的类不参与混淆,降低安全性
  • 不使用反射,改用if判断或者switch case

参考:1. https://stackoverflow.com/questions/41525867/reflection-not-working-on-android-release-apk-even-with-proguard-minify-disable

2.https://blog.csdn.net/guohesheng/article/details/53696652

3.https://www.jianshu.com/p/b5b2a5dfaaf4

感谢王志浩同学提供帮助!

  • avoid costly work in build() since build() can be invoked frequently when ancestor Widgets rebuild

  • avoid calling setState() high up in the tree

  • Use the lazy methods, with callbacks,when building large grids or lists, that way only the visible portion of the screen is built at startup time

  • avoid invoke saveLayer(),including

    • opacity widget
    • shaderMask
    • colorFilter
    • Clip
    • Text
    • addition:Clipping doesn’t call saveLayer() but is still costly

    Ways to avoid calls to saveLayer():

    • To implement fading in an image, consider using the FadeInImage
    • using the border Radius property instead of applying a clipping rectangle
  • build and display frames in 16ms

  • build subtree widget once and pass it as a child to the AnimatedBuilder

  • pre-clip image before animating it

  • avoid using constructors with a concrete List of children if most of the children are not visible on screen

source:https://flutter.dev/docs/perf/rendering/best-practices

to be continued

grasp

/ɡrɑːsp $ ɡræsp/

verb

1
1.I grasped his arm firmly and led him away

image

directive

/dəˈrektɪv/

noun

1
1.an official oeder or instruction

proposals for implementing the EU directive on paternity leave

image

allege

/əˈledʒ/

verb

1
1.to say that something is true,although it has not been proved

The water is alleged to be pollutedted with mercury.

image


medium

/ˈmiːdiəm/

noun

1
1.a way of communicating information and news to people,such as newspapers,television etc

Advertising is a powerful medium

image


tenure

/ˈtenjə/

noun

1
1.the right to stay permanently in a teaching job

It’s becoming increasingly difficult to acquire academic tenure

image


registration

/redʒɪˈstreɪʃən/

noun

1
1.the act of recording names on an official list

the registration of motor vehicles

image


ratify

[ˈrætɪfaɪ]

verb

1
to make a written agreement official by signing it

We hope that the republics will be willing to ratify the treaty.


instantaneous

/ˌɪnstənˈteɪniəs◂/

adj

1
happening immediately

modern methods of instantaneous communication

image


aid

/eɪd/

noun

1
something such as a machine or tool that helps someone do something

A video is a useful aid in the classroom

image


relay

/ˈriːleɪ/

verb

1
to pass a message from one person to another

relay something to somebody

image


semaphore

/ˈseməfɔː $ -fɔːr/

noun

1
a system of sending messages useing two flags,which you hold in different positions to represent letters and numbers

image


circuit

/ˈsɜːkɪt/

noun

1
a path that forms a circle around an area

we did a circuit of the old city

image


magnetism

/ˈmæɡnɪtɪzəm/

noun

1
the physical force that makes two metal objects pull toward each other or push each other apart

personal magnetism

image


squiggle

/ˈskwɪɡəl/

noun

1
a line with irregular curves

Shorthand just looks like a series of funny squiggles to me

image


paradigm

/ˈpærədaɪm/

noun

1
a very clear example of something

the basic paradigm of the family tree

image


patent

/ˈpeɪtnt/

noun

1
a special document that gives you the right to make or sell a new invention or product that no one else is allowed to copy

The drugs are protected by patent

image


refer

/rɪˈfɜː $ -ɜːr/

verb

1
1.to mention about something

We agreed never to refer to the matter again.

image


错误描述:在A类访问B类里的static 变量,永远是初始值,即使已经设置过新值

解决办法:A类import B类头文件时使用绝对路径,不使用系统默认

1
2
3
4
//错误
import 'package:xxx_app/utils/app_helper.dart';
//正确
import '../utils/app_helper.dart';

B类结构

1
2
3
4
5
6
7
class AppHelper {
static String name = "";

someFunction(){
name = "testName";
}
}

参考:https://stackoverflow.com/questions/45772318/flutter-dart-static-variables-lost-keep-getting-reinitialized

新词:

1
toy around

错误描述: pod install时发生错误

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
### Error

​```
NoMethodError - undefined method `size' for nil:NilClass
/Library/Ruby/Gems/2.6.0/gems/ruby-macho-1.4.0/lib/macho/macho_file.rb:455:in `populate_mach_header'
/Library/Ruby/Gems/2.6.0/gems/ruby-macho-1.4.0/lib/macho/macho_file.rb:233:in `populate_fields'
/Library/Ruby/Gems/2.6.0/gems/ruby-macho-1.4.0/lib/macho/macho_file.rb:55:in `initialize_from_bin'
/Library/Ruby/Gems/2.6.0/gems/ruby-macho-1.4.0/lib/macho/macho_file.rb:33:in `new_from_bin'
/Library/Ruby/Gems/2.6.0/gems/ruby-macho-1.4.0/lib/macho/fat_file.rb:365:in `block in populate_machos'
/Library/Ruby/Gems/2.6.0/gems/ruby-macho-1.4.0/lib/macho/fat_file.rb:364:in `each'
/Library/Ruby/Gems/2.6.0/gems/ruby-macho-1.4.0/lib/macho/fat_file.rb:364:in `populate_machos'
/Library/Ruby/Gems/2.6.0/gems/ruby-macho-1.4.0/lib/macho/fat_file.rb:156:in `populate_fields'
/Library/Ruby/Gems/2.6.0/gems/ruby-macho-1.4.0/lib/macho/fat_file.rb:95:in `initialize'
/Library/Ruby/Gems/2.6.0/gems/ruby-macho-1.4.0/lib/macho.rb:31:in `new'
/Library/Ruby/Gems/2.6.0/gems/ruby-macho-1.4.0/lib/macho.rb:31:in `open'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.10.0/lib/cocoapods/xcode/linkage_analyzer.rb:16:in `dynamic_binary?'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.10.0/lib/cocoapods/sandbox/file_accessor.rb:171:in `block in vendored_dynamic_frameworks'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.10.0/lib/cocoapods/sandbox/file_accessor.rb:170:in `select'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.10.0/lib/cocoapods/sandbox/file_accessor.rb:170:in `vendored_dynamic_frameworks'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.10.0/lib/cocoapods/sandbox/file_accessor.rb:179:in `vendored_static_frameworks'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.10.0/lib/cocoapods/sandbox/file_accessor.rb:292:in `vendored_static_artifacts'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.10.0/lib/cocoapods/installer/xcode/target_validator.rb:82:in `each'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.10.0/lib/cocoapods/installer/xcode/target_validator.rb:82:in `flat_map'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.10.0/lib/cocoapods/installer/xcode/target_validator.rb:82:in `block (2 levels) in verify_no_static_framework_transitive_dependencies'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.10.0/lib/cocoapods/installer/xcode/target_validator.rb:74:in `each_key'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.10.0/lib/cocoapods/installer/xcode/target_validator.rb:74:in `block in verify_no_static_framework_transitive_dependencies'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.10.0/lib/cocoapods/installer/xcode/target_validator.rb:73:in `each'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.10.0/lib/cocoapods/installer/xcode/target_validator.rb:73:in `verify_no_static_framework_transitive_dependencies'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.10.0/lib/cocoapods/installer/xcode/target_validator.rb:38:in `validate!'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.10.0/lib/cocoapods/installer.rb:595:in `validate_targets'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.10.0/lib/cocoapods/installer.rb:162:in `install!'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.10.0/lib/cocoapods/command/install.rb:52:in `run'
/Library/Ruby/Gems/2.6.0/gems/claide-1.0.3/lib/claide/command.rb:334:in `run'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.10.0/lib/cocoapods/command.rb:52:in `run'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.10.0/bin/pod:55:in `<top (required)>'
/usr/local/bin/pod:23:in `load'
/usr/local/bin/pod:23:in `<main>'
​```

――― TEMPLATE END ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――

[!] Oh no, an error occurred.

Search for existing GitHub issues similar to yours:
https://github.com/CocoaPods/CocoaPods/search?q=undefined+method+%60size%27+for+nil%3ANilClass&type=Issues

If none exists, create a ticket, with the template displayed above, on:
https://github.com/CocoaPods/CocoaPods/issues/new

Be sure to first read the contributing guide for details on how to properly submit a ticket:
https://github.com/CocoaPods/CocoaPods/blob/master/CONTRIBUTING.md

Don't forget to anonymize any private data!

Looking for related issues on cocoapods/cocoapods...
- NoMethodError - undefined method `size' for nil:NilClass
https://github.com/CocoaPods/CocoaPods/issues/10426 [closed] [3 comments]
a week ago

- NoMethodError - undefined method `size' for nil:NilClass
https://github.com/CocoaPods/CocoaPods/issues/10273 [closed] [3 comments]
7 weeks ago

- NoMethodError - undefined method `size' for nil:NilClass
https://github.com/CocoaPods/CocoaPods/issues/8377 [closed] [24 comments]
a week ago

and 8 more at:
https://github.com/cocoapods/cocoapods/search?q=undefined%20method%20%60size%27%20for%20nil&type=Issues&utf8=✓

解决办法:在flutter目录运行以下命令

1
2
3
4
5
flutter clean
rm -Rf ios/Pods
rm -Rf ios/.symlinks
rm -Rf ios/Flutter/Flutter.framework
rm -Rf ios/Flutter/Flutter.podspec

参考:https://github.com/CocoaPods/CocoaPods/issues/8377

问题:在build的时候framework not found

解决:

  • 添加需要的framework
  • 确定framework齐全的情况下,就是系统添加了冗余的framework编译需求,找到require列表删除即可
1
project.xcodeproj文件--->显示包内容--->project.pbxproj文件 全局查找删除

ps:版本对不上处理方法同理,修改版本号和实际pods下载过来一致

问题:

1
2
3
4
5
6
7
8
9
fatal: unable to access 'https://github.com/xxx/xxx.github.io.git/': LibreSSL SSL_connect: SSL_ERROR_SYSCALL in connection to github.com:443 
FATAL {
err: Error: Spawn failed
at ChildProcess.<anonymous> (/Users/kevin/Desktop/xxx.github.io/node_modules/hexo-deployer-git/node_modules/hexo-util/lib/spawn.js:51:21)
at ChildProcess.emit (events.js:315:20)
at Process.ChildProcess._handle.onexit (internal/child_process.js:277:12) {
code: 128
}
} Something's wrong. Maybe you can find the solution here: %s https://hexo.io/docs/troubleshooting.html

解决:在_config.yml文件里把deploy的地址从http换成git

1
2
3
4
5
6
deploy:
type: git
#repo: https://github.com/xxx/xxx.github.io.git
repo: git@github.com:xxx/xxx.github.io.git
branch: master

  • 原生webview加载耗时

    • 预热webview,并且缓存多个对象进行复用
  • webview网络请求页面内容,下载html

    • 在未点开网页时,用网络请求框架异步请求html内容,保存到本地缓存框架中
    • 在移动端启动local web server,同步服务器资源到本地,h5链接替换成localhost+port链接,例如swift版本的Telegraph
    • 本地网络框架请求zip资源并解压,供WKWebview的WKURLSchemeHandler拦截网络请求并调用(例如把http替换为自动以scheme)
  • 解析html

    • webview请求网络前先本地缓存查找已经下载好的html内容,直接进行加载渲染
  • 请求js、css资源

    • 本地网络框架选择性下载较大图片文件
  • 正常页面加载顺序为拿到html,计算布局,识别外链资源,绘制渲染

    • 后端直接加载好页面依赖的css,js和接口数据,拼接好一个最终版html返回给前端
  • 接口耗时长

    • 更新接口的处理方式
    • 增加占位图,优化体验
  • 内存泄露

    • 及时释放图片和数组等资源

参考链接: