-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsearch.xml
2137 lines (1717 loc) · 735 KB
/
search.xml
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>Android 源码编译</title>
<url>/2021/11/27/Android%20%E6%BA%90%E7%A0%81%E7%BC%96%E8%AF%91/</url>
<content><![CDATA[<h3 id="Perpare-Env"><a href="#Perpare-Env" class="headerlink" title="Perpare Env"></a>Perpare Env</h3><h4 id="下载-repo-工具"><a href="#下载-repo-工具" class="headerlink" title="下载 repo 工具:"></a>下载 repo 工具:</h4><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line">mkdir ~/bin</span><br><span class="line">PATH=~/bin:<span class="variable">$PATH</span></span><br><span class="line"><span class="built_in">curl</span> https://storage.googleapis.com/git<span class="literal">-repo-downloads</span>/repo > ~/bin/repo</span><br><span class="line">chmod a+x ~/bin/repo</span><br></pre></td></tr></table></figure>
<h4 id="使用每月更新的初始化包"><a href="#使用每月更新的初始化包" class="headerlink" title="使用每月更新的初始化包"></a>使用每月更新的初始化包</h4><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">wget -c https://mirrors.tuna.tsinghua.edu.cn/aosp-monthly/aosp-latest.tar # 下载初始化包</span><br><span class="line">tar xf aosp-latest.tar</span><br><span class="line">cd AOSP # 解压得到的 AOSP 工程目录</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">这时 <span class="built_in">ls</span> 的话什么也看不到,因为只有一个隐藏的 .repo 目录</span></span><br><span class="line">repo sync # 正常同步一遍即可得到完整目录</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">或 repo <span class="built_in">sync</span> -l 仅checkout代码</span></span><br></pre></td></tr></table></figure>
<span id="more"></span>
<h4 id="初始化仓库"><a href="#初始化仓库" class="headerlink" title="初始化仓库:"></a>初始化仓库:</h4><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest</span><br></pre></td></tr></table></figure>
<p><strong>如果提示无法连接到 gerrit.googlesource.com,请参照</strong><a href="https://mirrors.tuna.tsinghua.edu.cn/help/git-repo"><strong>git-repo的帮助页面</strong></a><strong>的更新一节。</strong></p>
<h4 id="如果需要某个特定的-Android-版本-列表-:"><a href="#如果需要某个特定的-Android-版本-列表-:" class="headerlink" title="如果需要某个特定的 Android 版本(列表):"></a>如果需要某个特定的 Android 版本(<a href="https://source.android.com/setup/start/build-numbers#source-code-tags-and-builds">列表</a>):</h4><p>master branch maybe no pass</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest -b android-4.0.1_r1</span><br></pre></td></tr></table></figure>
<h4 id="同步源码树(以后只需执行这条命令来同步):"><a href="#同步源码树(以后只需执行这条命令来同步):" class="headerlink" title="同步源码树(以后只需执行这条命令来同步):"></a>同步源码树(以后只需执行这条命令来同步):</h4><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">repo sync</span><br></pre></td></tr></table></figure>
<h4 id="install-dependencies-for-ubuntu-20-04"><a href="#install-dependencies-for-ubuntu-20-04" class="headerlink" title="install dependencies for ubuntu 20.04"></a>install dependencies for ubuntu 20.04</h4><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">java</span></span><br><span class="line">sudo apt-get update</span><br><span class="line">sudo apt-get install openjdk-8-jdk</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">dependencies</span></span><br><span class="line">sudo apt install git-core gnupg flex bison gperf build-essential zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z-dev libgl1-mesa-dev libxml2-utils xsltproc unzip</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash"><span class="keyword">for</span> Ubuntu 20</span></span><br><span class="line">sudo apt-get install libncurses5</span><br></pre></td></tr></table></figure>
<h3 id="Build"><a href="#Build" class="headerlink" title="Build"></a>Build</h3><h4 id="First-set-Env"><a href="#First-set-Env" class="headerlink" title="First set Env"></a>First set Env</h4><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">source build/envsetup.sh</span><br></pre></td></tr></table></figure>
<h4 id="select-BUILD-and-BUILDTYPE"><a href="#select-BUILD-and-BUILDTYPE" class="headerlink" title="select BUILD and BUILDTYPE"></a>select BUILD and BUILDTYPE</h4><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">method 1 : select direct</span></span><br><span class="line">lunch aosp_arm64-eng</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">method 2 :list build, and select</span></span><br><span class="line">lunch</span><br></pre></td></tr></table></figure>
<h4 id="build"><a href="#build" class="headerlink" title="build"></a>build</h4><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">make -j12</span><br></pre></td></tr></table></figure>
<h4 id="Test"><a href="#Test" class="headerlink" title="Test"></a>Test</h4><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">source build/envsetup.sh</span><br><span class="line">lunch(选择刚才你设置的目标版本,比如这里了我选择的是2)</span><br><span class="line">emulator</span><br><span class="line"></span><br><span class="line">export ANDROID_SDK_ROOT=/home/xxx/Android/Sdk</span><br><span class="line">emulator -list-avds</span><br><span class="line">emulator -avd Pixel_3a_API_30 -ramdisk ramdisk.img -system system.img -data userdata.img</span><br></pre></td></tr></table></figure>
<h4 id="system-img"><a href="#system-img" class="headerlink" title="system.img"></a>system.img</h4><p>系统镜像,用于存储Android系统的核心文件,对应于系统的 <code>system</code> 目录,主要内容如下:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">apex bin etc framework lib64 product usr xbin</span><br><span class="line">app build.prop fonts lib priv-app system_ext vendor</span><br></pre></td></tr></table></figure>
<h4 id="userdata-img"><a href="#userdata-img" class="headerlink" title="userdata.img"></a>userdata.img</h4><p>用户镜像,用来存储与用户数据相关的数据</p>
<h4 id="ramdisk-img"><a href="#ramdisk-img" class="headerlink" title="ramdisk.img"></a>ramdisk.img</h4><p>内存磁盘镜像,用于存储Linux内核启动时要装载的核心文件,对应 <code>root</code> 目录</p>
<h4 id="vendor-img"><a href="#vendor-img" class="headerlink" title="vendor.img"></a>vendor.img</h4><p>驱动镜像,带有品牌标识和驱动的包,系统和驱动分开,方便以后升级系统</p>
<h4 id="cache-img"><a href="#cache-img" class="headerlink" title="cache.img"></a>cache.img</h4><p>缓存镜像,用来进行系统升级或recovery</p>
<h3 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h3><ul>
<li>build : <a href="https://www.jianshu.com/p/367f0886e62b">https://www.jianshu.com/p/367f0886e62b</a></li>
</ul>
]]></content>
<categories>
<category>Android</category>
</categories>
<tags>
<tag>Android</tag>
</tags>
</entry>
<entry>
<title>C++ Hook</title>
<url>/2021/11/21/C++%20Hook/</url>
<content><![CDATA[<h2 id="C-Hook"><a href="#C-Hook" class="headerlink" title="C++ Hook"></a>C++ Hook</h2><h3 id="LD-PRELOAD-预加载hook-so"><a href="#LD-PRELOAD-预加载hook-so" class="headerlink" title="LD_PRELOAD 预加载hook so"></a>LD_PRELOAD 预加载hook so</h3><p>通过<code>LD_PRELOAD</code></p>
<figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><string.h></span></span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">if</span>( <span class="built_in">strcmp</span>(argv[<span class="number">1</span>], <span class="string">"password"</span>) )</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Incorrect password\n"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Correct password\n"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">gcc -o main main.c</span><br></pre></td></tr></table></figure>
<span id="more"></span>
<figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><string.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><dlfcn.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="title function_">int</span><span class="params">(*Fun)</span><span class="params">(<span class="type">const</span> <span class="type">char</span>*, <span class="type">const</span> <span class="type">char</span>*)</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">strcmp</span><span class="params">(<span class="type">const</span> <span class="type">char</span>* s1, <span class="type">const</span> <span class="type">char</span>* s2)</span></span><br><span class="line">{</span><br><span class="line"> <span class="type">static</span> <span class="type">void</span>* handle = <span class="literal">NULL</span>;</span><br><span class="line"> <span class="type">static</span> Fun org_strcmp = <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span>(!handle)</span><br><span class="line"> { <span class="comment">//解析得到真实的strcmp函数</span></span><br><span class="line"> handle = dlopen(<span class="string">"libc.so.6"</span>, RTLD_LAZY);</span><br><span class="line"> org_strcmp = (Fun)dlsym(handle, <span class="string">"strcmp"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//做我们想做的</span></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Hacked by way of ld_preload\n\n\n"</span>);</span><br><span class="line"> <span class="comment">//完成真实地功能</span></span><br><span class="line"> <span class="keyword">return</span> org_strcmp(s1, s2); </span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">gcc -fPIC -shared -o libmyhook.so my_hook.c -ldl</span><br></pre></td></tr></table></figure>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">LD_PRELOAD=./libmyhook.so ./main password </span><br></pre></td></tr></table></figure>
<h4 id="LD-PRELOAD"><a href="#LD-PRELOAD" class="headerlink" title="LD_PRELOAD"></a>LD_PRELOAD</h4><p>LD_PRELOAD,是个环境变量,用于动态库的加载,动态库加载的优先级最高,一般情况下,其加载顺序为LD_PRELOAD > LD_LIBRARY_PATH > /etc/ld.so.cache > /lib>/usr/lib。程序中我们经常要调用一些外部库的函数,以rand为例,如果我们有个自定义的rand函数,把它编译成动态库后,通过LD_PRELOAD加载,当程序中调用rand函数时,调用的其实是我们自定义的函数。</p>
<h4 id="dlsym参数"><a href="#dlsym参数" class="headerlink" title="dlsym参数"></a>dlsym参数</h4><p>RTLD_DEFAULT是在当前库中查找函数,而RTLD_NEXT则是在当前库之后查找第一次出现的函数。</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">#</span><span class="language-bash">define _GNU_SOURCE</span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">include <stdio.h></span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">include <string.h></span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">include <dlfcn.h></span></span><br><span class="line"></span><br><span class="line">typedef int(*Fun)(const char*, const char*);</span><br><span class="line"></span><br><span class="line">int strcmp(const char* s1, const char* s2)</span><br><span class="line">{</span><br><span class="line"> static Fun org_strcmp = NULL;</span><br><span class="line"></span><br><span class="line"> org_strcmp = (Fun)dlsym(RTLD_NEXT, "strcmp");</span><br><span class="line"> //做我们想做的</span><br><span class="line"> printf("Hacked by way of ld_preload\n\n\n");</span><br><span class="line"> //完成真实地功能</span><br><span class="line"> return org_strcmp(s1, s2); </span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>RTLD_NEXT找不到</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">#</span><span class="language-bash">define _GNU_SOURCE</span></span><br></pre></td></tr></table></figure>
<h4 id="dlopen参数"><a href="#dlopen参数" class="headerlink" title="dlopen参数"></a>dlopen参数</h4><p>RTLD_LAZY:在dlopen返回前,对于动态库中存在的未定义的变量(如外部变量extern,也可以是函数)不执行解析,就是不解析这个变量的地址。<br>RTLD_NOW:与上面不同,他需要在dlopen返回前,解析出每个未定义变量的地址,如果解析不出来,在dlopen会返回NULL,错误为: : undefined symbol: xxxx…….<br>RTLD_GLOBAL:它的含义是使得库中的解析的定义变量在随后的其它的链接库中变得可以使用。</p>
<h3 id="Android-Hook"><a href="#Android-Hook" class="headerlink" title="Android Hook"></a>Android Hook</h3><p><code>ZygotePreload</code> 在app创建前预加载一些库(java 或native),比如使用 <code>LD_PRELOAD</code></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">android:zygotePreloadName=<span class="string">"io.github.zauther.demo.ZygotePreload"</span></span><br><span class="line"></span><br><span class="line"><span class="meta">@Keep</span></span><br><span class="line"><span class="meta">@RequiresApi(api = Build.VERSION_CODES.Q)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ZygotePreload</span> <span class="keyword">implements</span> <span class="title class_">android</span>.app.ZygotePreload{</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">doPreload</span><span class="params">(<span class="meta">@NonNull</span> ApplicationInfo appInfo)</span> {</span><br><span class="line"> System.out.println(<span class="string">"==TEST=="</span>);</span><br><span class="line"> Log.i(<span class="string">"==TEST=="</span>,<span class="string">"ZygotePreload:"</span>+appInfo.dataDir);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="通过符号表Hook对应的方法"><a href="#通过符号表Hook对应的方法" class="headerlink" title="通过符号表Hook对应的方法"></a>通过符号表Hook对应的方法</h3><h4 id="定义函数指针-lookup"><a href="#定义函数指针-lookup" class="headerlink" title="定义函数指针 lookup"></a>定义函数指针 lookup</h4><p>lookup需要跟实际调用方法参数保持一致</p>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="type">void</span>* (*lookup)(<span class="type">void</span>*, <span class="type">char</span> <span class="type">const</span>*, <span class="type">unsigned</span> <span class="type">int</span>);</span><br></pre></td></tr></table></figure>
<h4 id="找到so对应位置"><a href="#找到so对应位置" class="headerlink" title="找到so对应位置"></a>找到so对应位置</h4><ul>
<li>fdlopen 打开so库</li>
<li>fdlsym 找到符号表位置</li>
</ul>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line">std::string soPath = <span class="string">"/system/"</span>;</span><br><span class="line"><span class="keyword">if</span> (<span class="built_in">get_api_level</span>() > <span class="number">29</span>) {</span><br><span class="line"> soPath = <span class="string">"/apex/com.android.art/"</span>;</span><br><span class="line">}<span class="keyword">else</span> <span class="keyword">if</span> (<span class="built_in">get_api_level</span>() == <span class="number">29</span>) {</span><br><span class="line"> soPath = <span class="string">"/apex/com.android.runtime/"</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> *handle = <span class="built_in">fdlopen</span>((soPath + <span class="string">"lib/libart.so"</span>).<span class="built_in">c_str</span>(), RTLD_LAZY);</span><br><span class="line"><span class="keyword">if</span> (handle == <span class="literal">nullptr</span>) {</span><br><span class="line"> handle = <span class="built_in">fdlopen</span>((soPath + <span class="string">"lib64/libart.so"</span>).<span class="built_in">c_str</span>(), RTLD_LAZY);</span><br><span class="line"> <span class="keyword">if</span> (handle == <span class="literal">nullptr</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> lookup = (<span class="type">void</span>* (*)(<span class="type">void</span>* prt, <span class="type">char</span> <span class="type">const</span>*, <span class="type">unsigned</span> <span class="type">int</span>))<span class="built_in">fdlsym</span>(handle, <span class="string">"_ZN3art10ClassTable6LookupEPKcm"</span>);</span><br><span class="line"> <span class="keyword">if</span> (lookup == <span class="literal">nullptr</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line">} <span class="keyword">else</span> {</span><br><span class="line"> lookup = (<span class="type">void</span>* (*)(<span class="type">void</span>* prt, <span class="type">char</span> <span class="type">const</span>*, <span class="type">unsigned</span> <span class="type">int</span>))<span class="built_in">fdlsym</span>(handle, <span class="string">"_ZN3art10ClassTable6LookupEPKcj"</span>);</span><br><span class="line"> <span class="keyword">if</span> (lookup == <span class="literal">nullptr</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">return</span> <span class="literal">true</span>;</span><br></pre></td></tr></table></figure>
<h4 id="函数调用"><a href="#函数调用" class="headerlink" title="函数调用"></a>函数调用</h4><figure class="highlight c++"><table><tr><td class="code"><pre><span class="line">(*lookup)((<span class="type">void</span> *)classTableAddr, descriptor.<span class="built_in">c_str</span>(), descriptor_hash);</span><br></pre></td></tr></table></figure>
<p>demo</p>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="keyword">for</span> (jsize i = <span class="number">0</span>; i < env-><span class="built_in">GetArrayLength</span>(classNames); i++) {</span><br><span class="line"> jstring className = (jstring)env-><span class="built_in">GetObjectArrayElement</span>(classNames, i);</span><br><span class="line"> <span class="type">const</span> <span class="type">char</span>* name = env-><span class="built_in">GetStringUTFChars</span>(className, <span class="literal">nullptr</span>);</span><br><span class="line"> <span class="keyword">if</span> (name == <span class="literal">nullptr</span>) {</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"> env-><span class="built_in">DeleteLocalRef</span>(className);</span><br><span class="line"> <span class="function">std::string <span class="title">descriptor</span><span class="params">(DotToDescriptor(name))</span></span>;</span><br><span class="line"> <span class="type">const</span> <span class="type">size_t</span> descriptor_hash = <span class="built_in">ComputeModifiedUtf8Hash</span>(descriptor.<span class="built_in">c_str</span>());</span><br><span class="line"> <span class="type">void</span>* addr = (*lookup)((<span class="type">void</span> *)classTableAddr, descriptor.<span class="built_in">c_str</span>(), descriptor_hash);</span><br><span class="line"> <span class="keyword">if</span> (addr == <span class="literal">nullptr</span>) {</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"> vector.<span class="built_in">push_back</span>(name);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
]]></content>
<categories>
<category>Android</category>
</categories>
<tags>
<tag>Android</tag>
<tag>C++</tag>
</tags>
</entry>
<entry>
<title>Android Native开发</title>
<url>/2019/07/02/Android-Native%E5%BC%80%E5%8F%91/</url>
<content><![CDATA[<h2 id="Android-Native开发"><a href="#Android-Native开发" class="headerlink" title="Android Native开发"></a>Android Native开发</h2><p>Android 从</p>
<h3 id="0x01-JNI-开发"><a href="#0x01-JNI-开发" class="headerlink" title="0x01 JNI 开发"></a>0x01 JNI 开发</h3><h4 id="1-Demo"><a href="#1-Demo" class="headerlink" title="1. Demo"></a>1. Demo</h4><p>我们现来看一个例子。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">HelloJni</span> {</span><br><span class="line"> <span class="keyword">static</span> {</span><br><span class="line"> System.loadLibrary(<span class="string">"native-lib"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">native</span> String <span class="title function_">stringFromJNI</span><span class="params">()</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><jni.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><string></span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">extern</span> <span class="string">"C"</span></span><br><span class="line"><span class="function">JNIEXPORT jstring JNICALL</span></span><br><span class="line"><span class="function"><span class="title">Java_cn_cwiki_someapp_test_HelloJni_stringFromJNI</span><span class="params">(JNIEnv *env, jclass type)</span> </span>{</span><br><span class="line"> <span class="comment">// TODO</span></span><br><span class="line"> <span class="keyword">return</span> env-><span class="built_in">NewStringUTF</span>(<span class="string">"Hello, Java Native Interface!"</span>);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">extern</span> <span class="string">"C"</span></span><br><span class="line"><span class="function">JNIEXPORT jstring JNICALL</span></span><br><span class="line"><span class="function"><span class="title">Java_cn_cwiki_someapp_test_HelloJni_test</span><span class="params">(JNIEnv *env, jobject instance)</span> </span>{</span><br><span class="line"> <span class="comment">// TODO</span></span><br><span class="line"> <span class="keyword">return</span> env-><span class="built_in">NewStringUTF</span>(<span class="string">"test"</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p><img src="/images/image-20190628232500731.webp" alt="image-20190628232500731"></p>
<figure class="highlight cmake"><table><tr><td class="code"><pre><span class="line"><span class="keyword">cmake_minimum_required</span>(VERSION <span class="number">3.4</span>.<span class="number">1</span>)</span><br><span class="line"><span class="keyword">add_library</span>(</span><br><span class="line"> native-lib SHARED</span><br><span class="line"> src/main/cpp/native-lib.cpp</span><br><span class="line">)</span><br><span class="line"><span class="keyword">target_link_libraries</span>(</span><br><span class="line"> native-lib</span><br><span class="line"> src/main/cpp/native-lib.cpp</span><br><span class="line">)</span><br></pre></td></tr></table></figure>
<figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line">android {</span><br><span class="line"> ...</span><br><span class="line"> externalNativeBuild {</span><br><span class="line"> cmake {</span><br><span class="line"> path <span class="string">"CMakeLists.txt"</span> <span class="comment">//CMakeLists.txt的路径</span></span><br><span class="line"> version <span class="string">"3.10.2"</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> ...</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p><img src="/images/image-20190628233820985.webp" alt="image-20190628233820985"></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="type">String</span> <span class="variable">stringFromJNI</span> <span class="operator">=</span> HelloJni.stringFromJNI();</span><br></pre></td></tr></table></figure>
<p><img src="/images/image-20190628234045501.webp" alt="image-20190628234045501"></p>
<span id="more"></span>
<h4 id="2-Java-Native-Interface-Jni-:"><a href="#2-Java-Native-Interface-Jni-:" class="headerlink" title="2. Java Native Interface(Jni):"></a>2. Java Native Interface(Jni):</h4><p>jni.h</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="type">uint8_t</span> jboolean; <span class="comment">/* unsigned 8 bits */</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">int8_t</span> jbyte; <span class="comment">/* signed 8 bits */</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">uint16_t</span> jchar; <span class="comment">/* unsigned 16 bits */</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">int16_t</span> jshort; <span class="comment">/* signed 16 bits */</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">int32_t</span> jint; <span class="comment">/* signed 32 bits */</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">int64_t</span> jlong; <span class="comment">/* signed 64 bits */</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">float</span> jfloat; <span class="comment">/* 32-bit IEEE 754 */</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">double</span> jdouble; <span class="comment">/* 64-bit IEEE 754 */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * Reference types, in C.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">void</span>* jobject;</span><br><span class="line"><span class="keyword">typedef</span> jobject jclass;</span><br><span class="line"><span class="keyword">typedef</span> jobject jstring;</span><br><span class="line"><span class="keyword">typedef</span> jobject jarray;</span><br><span class="line"><span class="keyword">typedef</span> jarray jobjectArray;</span><br><span class="line"><span class="keyword">typedef</span> jarray jbooleanArray;</span><br><span class="line"><span class="keyword">typedef</span> jarray jbyteArray;</span><br><span class="line"><span class="keyword">typedef</span> jarray jcharArray;</span><br><span class="line"><span class="keyword">typedef</span> jarray jshortArray;</span><br><span class="line"><span class="keyword">typedef</span> jarray jintArray;</span><br><span class="line"><span class="keyword">typedef</span> jarray jlongArray;</span><br><span class="line"><span class="keyword">typedef</span> jarray jfloatArray;</span><br><span class="line"><span class="keyword">typedef</span> jarray jdoubleArray;</span><br><span class="line"><span class="keyword">typedef</span> jobject jthrowable;</span><br><span class="line"><span class="keyword">typedef</span> jobject jweak;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">if</span> defined(__cplusplus)</span></span><br><span class="line"><span class="keyword">typedef</span> _JNIEnv JNIEnv;</span><br><span class="line"><span class="keyword">typedef</span> _JavaVM JavaVM;</span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">const</span> <span class="keyword">struct</span> <span class="title class_">JNINativeInterface</span>* JNIEnv;</span><br><span class="line"><span class="keyword">typedef</span> <span class="type">const</span> <span class="keyword">struct</span> <span class="title class_">JNIInvokeInterface</span>* JavaVM;</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br></pre></td></tr></table></figure>
<h3 id="0x02-NDK-开发"><a href="#0x02-NDK-开发" class="headerlink" title="0x02 NDK 开发"></a>0x02 NDK 开发</h3><p>CMake配置:</p>
<figure class="highlight cmake"><table><tr><td class="code"><pre><span class="line"><span class="keyword">cmake_minimum_required</span>(VERSION <span class="number">3.4</span>.<span class="number">1</span>)</span><br><span class="line"><span class="keyword">add_library</span>(native_app_glue STATIC</span><br><span class="line"> <span class="variable">${ANDROID_NDK}</span>/sources/android/native_app_glue/android_native_app_glue.c)</span><br><span class="line"><span class="keyword">add_library</span>(main SHARED <span class="variable">${CMAKE_SOURCE_DIR}</span>/src/main/cpp/main.cpp)</span><br><span class="line"><span class="keyword">target_include_directories</span>(main PRIVATE</span><br><span class="line"> <span class="variable">${ANDROID_NDK}</span>/sources/android/native_app_glue)</span><br><span class="line"><span class="keyword">target_link_libraries</span>(</span><br><span class="line"> main</span><br><span class="line"> android</span><br><span class="line"> native_app_glue</span><br><span class="line"> EGL</span><br><span class="line"> GLESv1_CM</span><br><span class="line"> log</span><br><span class="line">)</span><br></pre></td></tr></table></figure>
<p>AndroidManifest.xml</p>
<figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">application</span> <span class="attr">android:label</span>=<span class="string">"@string/app_name"</span> <span class="attr">android:hasCode</span>=<span class="string">"false"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">activity</span> <span class="attr">android:name</span>=<span class="string">"android.app.NativeActivity"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">android:label</span>=<span class="string">"@string/app_name"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">meta-data</span> <span class="attr">android:name</span>=<span class="string">"android.app.lib_name"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">android:value</span>=<span class="string">"main"</span>/></span></span><br><span class="line"> <span class="tag"><<span class="name">intent-filter</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">action</span> <span class="attr">android:name</span>=<span class="string">"android.intent.action.MAIN"</span>/></span></span><br><span class="line"> <span class="tag"><<span class="name">category</span> <span class="attr">android:name</span>=<span class="string">"android.intent.category.LAUNCHER"</span>/></span></span><br><span class="line"> <span class="tag"></<span class="name">intent-filter</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">activity</span>></span></span><br><span class="line"><span class="tag"></<span class="name">application</span>></span></span><br></pre></td></tr></table></figure>
<p>Main.cpp</p>
<figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * Copyright (C) 2010 The Android Open Source Project</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Licensed under the Apache License, Version 2.0 (the "License");</span></span><br><span class="line"><span class="comment"> * you may not use this file except in compliance with the License.</span></span><br><span class="line"><span class="comment"> * You may obtain a copy of the License at</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * http://www.apache.org/licenses/LICENSE-2.0</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Unless required by applicable law or agreed to in writing, software</span></span><br><span class="line"><span class="comment"> * distributed under the License is distributed on an "AS IS" BASIS,</span></span><br><span class="line"><span class="comment"> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.</span></span><br><span class="line"><span class="comment"> * See the License for the specific language governing permissions and</span></span><br><span class="line"><span class="comment"> * limitations under the License.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//BEGIN_INCLUDE(all)</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><initializer_list></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><memory></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstdlib></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cstring></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><jni.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><errno.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><cassert></span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><EGL/egl.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><GLES/gl.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><android/sensor.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><android/log.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><android_native_app_glue.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><android/bitmap.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><GrContext.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><SkGpuDevice.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><gl/GrGLInterface.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><GrContext.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><SkCanvas.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><SkGraphics.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><SkSurface.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><SkString.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><SkTime.h></span></span></span><br><span class="line"><span class="meta">#import <span class="string">"GrBackendSemaphore.h"</span></span></span><br><span class="line"><span class="meta">#import <span class="string"><GLES/gl.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><core/SkExecutor.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">"cpp/skia/WindowContextFactory_android.h"</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">"cpp/skia/Window.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, <span class="string">"native-activity"</span>, __VA_ARGS__))</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, <span class="string">"native-activity"</span>, __VA_ARGS__))</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Our saved state data.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">saved_state</span> {</span><br><span class="line"> <span class="type">float</span> angle;</span><br><span class="line"> <span class="type">int32_t</span> x;</span><br><span class="line"> <span class="type">int32_t</span> y;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Shared state for our app.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">engine</span> {</span><br><span class="line"> <span class="keyword">struct</span> <span class="title class_">android_app</span> *app;</span><br><span class="line"> ASensorManager *sensorManager;</span><br><span class="line"> <span class="type">const</span> ASensor *accelerometerSensor;</span><br><span class="line"> ASensorEventQueue *sensorEventQueue;</span><br><span class="line"> <span class="type">int</span> animating;</span><br><span class="line"> EGLDisplay display;</span><br><span class="line"> EGLSurface surface;</span><br><span class="line"> EGLContext context;</span><br><span class="line"> <span class="type">int32_t</span> width;</span><br><span class="line"> <span class="type">int32_t</span> height;</span><br><span class="line"> <span class="keyword">struct</span> <span class="title class_">saved_state</span> state;</span><br><span class="line"></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">static</span> <span class="type">int</span> <span class="title">init_es_egl</span><span class="params">(<span class="keyword">struct</span> engine *engine)</span> </span>{</span><br><span class="line"> <span class="comment">// initialize OpenGL ES and EGL</span></span><br><span class="line"> <span class="comment">/*</span></span><br><span class="line"><span class="comment"> * Here specify the attributes of the desired configuration.</span></span><br><span class="line"><span class="comment"> * Below, we select an EGLConfig with at least 8 bits per color</span></span><br><span class="line"><span class="comment"> * component compatible with on-screen windows</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="type">const</span> EGLint attribs[] = {</span><br><span class="line"> EGL_SURFACE_TYPE, EGL_WINDOW_BIT,</span><br><span class="line"> EGL_BLUE_SIZE, <span class="number">8</span>,</span><br><span class="line"> EGL_GREEN_SIZE, <span class="number">8</span>,</span><br><span class="line"> EGL_RED_SIZE, <span class="number">8</span>,</span><br><span class="line"> EGL_NONE</span><br><span class="line"> };</span><br><span class="line"> EGLint w, h, format;</span><br><span class="line"> EGLint numConfigs;</span><br><span class="line"> EGLConfig config;</span><br><span class="line"> EGLSurface surface;</span><br><span class="line"> EGLContext context;</span><br><span class="line"> EGLDisplay display = <span class="built_in">eglGetDisplay</span>(EGL_DEFAULT_DISPLAY);</span><br><span class="line"> <span class="built_in">eglInitialize</span>(display, <span class="number">0</span>, <span class="number">0</span>);</span><br><span class="line"> <span class="built_in">SkAssertResult</span>(<span class="built_in">eglBindAPI</span>(EGL_OPENGL_ES_API));</span><br><span class="line"> <span class="comment">/* Here, the application chooses the configuration it desires.</span></span><br><span class="line"><span class="comment"> * find the best match if possible, otherwise use the very first one</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="built_in">eglChooseConfig</span>(display, attribs, <span class="literal">nullptr</span>, <span class="number">0</span>, &numConfigs);</span><br><span class="line"> <span class="function">std::unique_ptr<EGLConfig[]> <span class="title">supportedConfigs</span><span class="params">(<span class="keyword">new</span> EGLConfig[numConfigs])</span></span>;</span><br><span class="line"> <span class="built_in">assert</span>(supportedConfigs);</span><br><span class="line"> <span class="built_in">eglChooseConfig</span>(display, attribs, supportedConfigs.<span class="built_in">get</span>(), numConfigs, &numConfigs);</span><br><span class="line"> <span class="built_in">assert</span>(numConfigs);</span><br><span class="line"> <span class="keyword">auto</span> i = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (; i < numConfigs; i++) {</span><br><span class="line"> <span class="keyword">auto</span> &cfg = supportedConfigs[i];</span><br><span class="line"> EGLint r, g, b, d;</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">eglGetConfigAttrib</span>(display, cfg, EGL_RED_SIZE, &r) &&</span><br><span class="line"> <span class="built_in">eglGetConfigAttrib</span>(display, cfg, EGL_GREEN_SIZE, &g) &&</span><br><span class="line"> <span class="built_in">eglGetConfigAttrib</span>(display, cfg, EGL_BLUE_SIZE, &b) &&</span><br><span class="line"> <span class="built_in">eglGetConfigAttrib</span>(display, cfg, EGL_DEPTH_SIZE, &d) &&</span><br><span class="line"> r == <span class="number">8</span> && g == <span class="number">8</span> && b == <span class="number">8</span> && d == <span class="number">0</span>) {</span><br><span class="line"></span><br><span class="line"> config = supportedConfigs[i];</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (i == numConfigs) {</span><br><span class="line"> config = supportedConfigs[<span class="number">0</span>];</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">/* EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is</span></span><br><span class="line"><span class="comment"> * guaranteed to be accepted by ANativeWindow_setBuffersGeometry().</span></span><br><span class="line"><span class="comment"> * As soon as we picked a EGLConfig, we can safely reconfigure the</span></span><br><span class="line"><span class="comment"> * ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID. */</span></span><br><span class="line"> <span class="built_in">eglGetConfigAttrib</span>(display, config, EGL_NATIVE_VISUAL_ID, &format);</span><br><span class="line"> surface = <span class="built_in">eglCreateWindowSurface</span>(display, config, engine->app->window, <span class="literal">NULL</span>);</span><br><span class="line"> context = <span class="built_in">eglCreateContext</span>(display, config, <span class="literal">NULL</span>, <span class="literal">NULL</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">eglMakeCurrent</span>(display, surface, surface, context) == EGL_FALSE) {</span><br><span class="line"> <span class="built_in">LOGW</span>(<span class="string">"Unable to eglMakeCurrent"</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">eglQuerySurface</span>(display, surface, EGL_WIDTH, &w);</span><br><span class="line"> <span class="built_in">eglQuerySurface</span>(display, surface, EGL_HEIGHT, &h);</span><br><span class="line"></span><br><span class="line"> engine->display = display;</span><br><span class="line"> engine->context = context;</span><br><span class="line"> engine->surface = surface;</span><br><span class="line"> engine->width = w;</span><br><span class="line"> engine->height = h;</span><br><span class="line"> engine->state.angle = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Check openGL on the system</span></span><br><span class="line"> <span class="keyword">auto</span> opengl_info = {GL_VENDOR, GL_RENDERER, GL_VERSION, GL_EXTENSIONS};</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">auto</span> name : opengl_info) {</span><br><span class="line"> <span class="keyword">auto</span> info = <span class="built_in">glGetString</span>(name);</span><br><span class="line"> <span class="built_in">LOGI</span>(<span class="string">"OpenGL Info: %s"</span>, info);</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">LOGI</span>(<span class="string">"Canvas size: %d x %d"</span>, w, h);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Initialize GL state.</span></span><br><span class="line"> <span class="built_in">glHint</span>(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);</span><br><span class="line"> <span class="built_in">glEnable</span>(GL_CULL_FACE);</span><br><span class="line"> <span class="built_in">glShadeModel</span>(GL_SMOOTH);</span><br><span class="line"> <span class="built_in">glDisable</span>(GL_DEPTH_TEST);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">eglSurfaceAttrib</span>(display, surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Initialize an EGL context for the current display.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="type">static</span> <span class="type">int</span> <span class="title">engine_init_display</span><span class="params">(<span class="keyword">struct</span> engine *engine)</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="type">int</span> r = <span class="built_in">init_es_egl</span>(engine);</span><br><span class="line"> <span class="keyword">if</span> (r != <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">return</span> r;</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">init_raster_skia</span>(engine);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">static</span> <span class="type">void</span> <span class="title">initEgl</span><span class="params">(<span class="keyword">struct</span> engine *engine)</span> </span>{</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Just the current frame in the display.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="type">static</span> <span class="type">void</span> <span class="title">engine_draw_frame</span><span class="params">(<span class="keyword">struct</span> engine *engine)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (engine->display == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="comment">// No display.</span></span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// Just fill the screen with a color.</span></span><br><span class="line"> <span class="built_in">glClearColor</span>(((<span class="type">float</span>) engine->state.x) / engine->width, engine->state.angle,</span><br><span class="line"> ((<span class="type">float</span>) engine->state.y) / engine->height, <span class="number">1</span>);</span><br><span class="line"> <span class="built_in">glClear</span>(GL_COLOR_BUFFER_BIT);</span><br><span class="line"> <span class="built_in">eglSwapBuffers</span>(engine->display, engine->surface);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Tear down the EGL context currently associated with the display.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="type">static</span> <span class="type">void</span> <span class="title">engine_term_display</span><span class="params">(<span class="keyword">struct</span> engine *engine)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (engine->display != EGL_NO_DISPLAY) {</span><br><span class="line"> <span class="built_in">eglMakeCurrent</span>(engine->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);</span><br><span class="line"> <span class="keyword">if</span> (engine->context != EGL_NO_CONTEXT) {</span><br><span class="line"> <span class="built_in">eglDestroyContext</span>(engine->display, engine->context);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (engine->surface != EGL_NO_SURFACE) {</span><br><span class="line"> <span class="built_in">eglDestroySurface</span>(engine->display, engine->surface);</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">eglTerminate</span>(engine->display);</span><br><span class="line"> }</span><br><span class="line"> engine->animating = <span class="number">0</span>;</span><br><span class="line"> engine->display = EGL_NO_DISPLAY;</span><br><span class="line"> engine->context = EGL_NO_CONTEXT;</span><br><span class="line"> engine->surface = EGL_NO_SURFACE;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Process the next input event.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="type">static</span> <span class="type">int32_t</span> <span class="title">engine_handle_input</span><span class="params">(<span class="keyword">struct</span> android_app *app, AInputEvent *event)</span> </span>{</span><br><span class="line"> <span class="keyword">struct</span> <span class="title class_">engine</span> *engine = (<span class="keyword">struct</span> engine *) app->userData;</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">AInputEvent_getType</span>(event) == AINPUT_EVENT_TYPE_MOTION) {</span><br><span class="line"> engine->animating = <span class="number">1</span>;</span><br><span class="line"> engine->state.x = <span class="built_in">AMotionEvent_getX</span>(event, <span class="number">0</span>);</span><br><span class="line"> engine->state.y = <span class="built_in">AMotionEvent_getY</span>(event, <span class="number">0</span>);</span><br><span class="line"> <span class="built_in">LOGI</span>(<span class="string">"touch %d,%d"</span>, engine->state.x, engine->state.y);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Process the next main command.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="type">static</span> <span class="type">void</span> <span class="title">engine_handle_cmd</span><span class="params">(<span class="keyword">struct</span> android_app *app, <span class="type">int32_t</span> cmd)</span> </span>{</span><br><span class="line"> <span class="keyword">struct</span> <span class="title class_">engine</span> *engine = (<span class="keyword">struct</span> engine *) app->userData;</span><br><span class="line"> <span class="keyword">switch</span> (cmd) {</span><br><span class="line"> <span class="keyword">case</span> APP_CMD_SAVE_STATE:</span><br><span class="line"> <span class="comment">// The system has asked us to save our current state. Do so.</span></span><br><span class="line"> engine->app->savedState = <span class="built_in">malloc</span>(<span class="built_in">sizeof</span>(<span class="keyword">struct</span> saved_state));</span><br><span class="line"> *((<span class="keyword">struct</span> saved_state *) engine->app->savedState) = engine->state;</span><br><span class="line"> engine->app->savedStateSize = <span class="built_in">sizeof</span>(<span class="keyword">struct</span> saved_state);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> APP_CMD_INIT_WINDOW:</span><br><span class="line"> <span class="comment">// The window is being shown, get it ready.</span></span><br><span class="line"> <span class="keyword">if</span> (engine->app->window != <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="built_in">engine_init_display</span>(engine);</span><br><span class="line"> <span class="built_in">engine_draw_frame</span>(engine);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> APP_CMD_TERM_WINDOW:</span><br><span class="line"> <span class="comment">// The window is being hidden or closed, clean it up.</span></span><br><span class="line"> <span class="built_in">engine_term_display</span>(engine);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> APP_CMD_GAINED_FOCUS:</span><br><span class="line"> <span class="comment">// When our app gains focus, we start monitoring the accelerometer.</span></span><br><span class="line"> <span class="keyword">if</span> (engine->accelerometerSensor != <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="built_in">ASensorEventQueue_enableSensor</span>(engine->sensorEventQueue,</span><br><span class="line"> engine->accelerometerSensor);</span><br><span class="line"> <span class="comment">// We'd like to get 60 events per second (in us).</span></span><br><span class="line"> <span class="built_in">ASensorEventQueue_setEventRate</span>(engine->sensorEventQueue,</span><br><span class="line"> engine->accelerometerSensor,</span><br><span class="line"> (<span class="number">1000L</span> / <span class="number">60</span>) * <span class="number">1000</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> APP_CMD_LOST_FOCUS:</span><br><span class="line"> <span class="comment">// When our app loses focus, we stop monitoring the accelerometer.</span></span><br><span class="line"> <span class="comment">// This is to avoid consuming battery while not being used.</span></span><br><span class="line"> <span class="keyword">if</span> (engine->accelerometerSensor != <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="built_in">ASensorEventQueue_disableSensor</span>(engine->sensorEventQueue,</span><br><span class="line"> engine->accelerometerSensor);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// Also stop animating.</span></span><br><span class="line"> engine->animating = <span class="number">0</span>;</span><br><span class="line"> <span class="built_in">engine_draw_frame</span>(engine);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * AcquireASensorManagerInstance(void)</span></span><br><span class="line"><span class="comment"> * Workaround ASensorManager_getInstance() deprecation false alarm</span></span><br><span class="line"><span class="comment"> * for Android-N and before, when compiling with NDK-r15</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><dlfcn.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="function">ASensorManager *<span class="title">AcquireASensorManagerInstance</span><span class="params">(android_app *app)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (!app)</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">nullptr</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">typedef</span> ASensorManager *(*PF_GETINSTANCEFORPACKAGE)(<span class="type">const</span> <span class="type">char</span> *name);</span><br><span class="line"> <span class="type">void</span> *androidHandle = <span class="built_in">dlopen</span>(<span class="string">"libandroid.so"</span>, RTLD_NOW);</span><br><span class="line"> PF_GETINSTANCEFORPACKAGE getInstanceForPackageFunc = (PF_GETINSTANCEFORPACKAGE)</span><br><span class="line"> <span class="built_in">dlsym</span>(androidHandle, <span class="string">"ASensorManager_getInstanceForPackage"</span>);</span><br><span class="line"> <span class="keyword">if</span> (getInstanceForPackageFunc) {</span><br><span class="line"> JNIEnv *env = <span class="literal">nullptr</span>;</span><br><span class="line"> app->activity->vm-><span class="built_in">AttachCurrentThread</span>(&env, <span class="literal">NULL</span>);</span><br><span class="line"></span><br><span class="line"> jclass android_content_Context = env-><span class="built_in">GetObjectClass</span>(app->activity->clazz);</span><br><span class="line"> jmethodID midGetPackageName = env-><span class="built_in">GetMethodID</span>(android_content_Context,</span><br><span class="line"> <span class="string">"getPackageName"</span>,</span><br><span class="line"> <span class="string">"()Ljava/lang/String;"</span>);</span><br><span class="line"> jstring packageName = (jstring) env-><span class="built_in">CallObjectMethod</span>(app->activity->clazz,</span><br><span class="line"> midGetPackageName);</span><br><span class="line"></span><br><span class="line"> <span class="type">const</span> <span class="type">char</span> *nativePackageName = env-><span class="built_in">GetStringUTFChars</span>(packageName, <span class="number">0</span>);</span><br><span class="line"> ASensorManager *mgr = <span class="built_in">getInstanceForPackageFunc</span>(nativePackageName);</span><br><span class="line"> env-><span class="built_in">ReleaseStringUTFChars</span>(packageName, nativePackageName);</span><br><span class="line"> app->activity->vm-><span class="built_in">DetachCurrentThread</span>();</span><br><span class="line"> <span class="keyword">if</span> (mgr) {</span><br><span class="line"> <span class="built_in">dlclose</span>(androidHandle);</span><br><span class="line"> <span class="keyword">return</span> mgr;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">typedef</span> ASensorManager *(*PF_GETINSTANCE)();</span><br><span class="line"> PF_GETINSTANCE getInstanceFunc = (PF_GETINSTANCE)</span><br><span class="line"> <span class="built_in">dlsym</span>(androidHandle, <span class="string">"ASensorManager_getInstance"</span>);</span><br><span class="line"> <span class="comment">// by all means at this point, ASensorManager_getInstance should be available</span></span><br><span class="line"> <span class="built_in">assert</span>(getInstanceFunc);</span><br><span class="line"> <span class="built_in">dlclose</span>(androidHandle);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">getInstanceFunc</span>();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * This is the main entry point of a native application that is using</span></span><br><span class="line"><span class="comment"> * android_native_app_glue. It runs in its own thread, with its own</span></span><br><span class="line"><span class="comment"> * event loop for receiving input events and doing other things.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">android_main</span><span class="params">(<span class="keyword">struct</span> android_app *state)</span> </span>{</span><br><span class="line"> <span class="keyword">struct</span> <span class="title class_">engine</span> engine;</span><br><span class="line"></span><br><span class="line"> <span class="built_in">memset</span>(&engine, <span class="number">0</span>, <span class="built_in">sizeof</span>(engine));</span><br><span class="line"> state->userData = &engine;</span><br><span class="line"> state->onAppCmd = engine_handle_cmd;</span><br><span class="line"> state->onInputEvent = engine_handle_input;</span><br><span class="line"> engine.app = state;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment">// Prepare to monitor accelerometer</span></span><br><span class="line"> engine.sensorManager = <span class="built_in">AcquireASensorManagerInstance</span>(state);</span><br><span class="line"> engine.accelerometerSensor = <span class="built_in">ASensorManager_getDefaultSensor</span>(</span><br><span class="line"> engine.sensorManager,</span><br><span class="line"> ASENSOR_TYPE_ACCELEROMETER);</span><br><span class="line"> engine.sensorEventQueue = <span class="built_in">ASensorManager_createEventQueue</span>(</span><br><span class="line"> engine.sensorManager,</span><br><span class="line"> state->looper, LOOPER_ID_USER,</span><br><span class="line"> <span class="literal">NULL</span>, <span class="literal">NULL</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (state->savedState != <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="comment">// We are starting with a previous saved state; restore from it.</span></span><br><span class="line"> engine.state = *(<span class="keyword">struct</span> saved_state *) state->savedState;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// loop waiting for stuff to do.</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">while</span> (<span class="literal">true</span>) {</span><br><span class="line"> <span class="comment">// Read all pending events.</span></span><br><span class="line"> <span class="type">int</span> ident;</span><br><span class="line"> <span class="type">int</span> events;</span><br><span class="line"> <span class="keyword">struct</span> <span class="title class_">android_poll_source</span> *source;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// If not animating, we will block forever waiting for events.</span></span><br><span class="line"> <span class="comment">// If animating, we loop until all events are read, then continue</span></span><br><span class="line"> <span class="comment">// to draw the next frame of animation.</span></span><br><span class="line"> <span class="keyword">while</span> ((ident = <span class="built_in">ALooper_pollAll</span>(engine.animating ? <span class="number">0</span> : <span class="number">-1</span>, <span class="literal">NULL</span>, &events,</span><br><span class="line"> (<span class="type">void</span> **) &source)) >= <span class="number">0</span>) {</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Process this event.</span></span><br><span class="line"> <span class="keyword">if</span> (source != <span class="literal">NULL</span>) {</span><br><span class="line"> source-><span class="built_in">process</span>(state, source);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// If a sensor has data, process it now.</span></span><br><span class="line"> <span class="keyword">if</span> (ident == LOOPER_ID_USER) {</span><br><span class="line"> <span class="keyword">if</span> (engine.accelerometerSensor != <span class="literal">NULL</span>) {</span><br><span class="line"> ASensorEvent event;</span><br><span class="line"> <span class="keyword">while</span> (<span class="built_in">ASensorEventQueue_getEvents</span>(engine.sensorEventQueue,</span><br><span class="line"> &event, <span class="number">1</span>) > <span class="number">0</span>) {</span><br><span class="line"> <span class="built_in">LOGI</span>(<span class="string">"accelerometer: x=%f y=%f z=%f"</span>,</span><br><span class="line"> event.acceleration.x, event.acceleration.y,</span><br><span class="line"> event.acceleration.z);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Check if we are exiting.</span></span><br><span class="line"> <span class="keyword">if</span> (state->destroyRequested != <span class="number">0</span>) {</span><br><span class="line"> <span class="built_in">engine_term_display</span>(&engine);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (engine.animating) {</span><br><span class="line"> <span class="comment">// Done with events; draw next animation frame.</span></span><br><span class="line"> engine.state.angle += <span class="number">.01</span>f;</span><br><span class="line"> <span class="keyword">if</span> (engine.state.angle > <span class="number">1</span>) {</span><br><span class="line"> engine.state.angle = <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Drawing is throttled to the screen update rate, so there</span></span><br><span class="line"> <span class="comment">// is no need to do timing here.</span></span><br><span class="line"> <span class="built_in">engine_draw_frame</span>(&engine);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">//END_INCLUDE(all)</span></span><br></pre></td></tr></table></figure>
<p>cmake中配置main.cpp和android_native_app_glue.c,编译成main.o动态库,供NativeActivity.java调用,Android App启动入口为Java的Activity(NativeActivity),NativeActivity加载main.o动态库,将执行过程交给Native代码android_native_app_glue.c,android_native_app_glue.c中包含了Native部分的启动方法,ANativeActivity_onCreate。</p>
<p> /<a href="http://androidxref.com/9.0.0_r3/xref/prebuilts/">prebuilts</a>/<a href="http://androidxref.com/9.0.0_r3/xref/prebuilts/ndk/">ndk</a>/<a href="http://androidxref.com/9.0.0_r3/xref/prebuilts/ndk/current/">current</a>/<a href="http://androidxref.com/9.0.0_r3/xref/prebuilts/ndk/current/sources/">sources</a>/<a href="http://androidxref.com/9.0.0_r3/xref/prebuilts/ndk/current/sources/android/">android</a>/<a href="http://androidxref.com/9.0.0_r3/xref/prebuilts/ndk/current/sources/android/native_app_glue/">native_app_glue</a>/<a href="http://androidxref.com/9.0.0_r3/xref/prebuilts/ndk/current/sources/android/native_app_glue/android_native_app_glue.c">android_native_app_glue.c</a> </p>
<figure class="highlight c"><table><tr><td class="code"><pre><span class="line">JNIEXPORT</span><br><span class="line"><span class="type">void</span> <span class="title function_">ANativeActivity_onCreate</span><span class="params">(ANativeActivity* activity, <span class="type">void</span>* savedState,</span></span><br><span class="line"><span class="params"> <span class="type">size_t</span> savedStateSize)</span>{</span><br><span class="line"> LOGV(<span class="string">"Creating: %p\n"</span>, activity);</span><br><span class="line"> activity->callbacks->onDestroy = onDestroy;</span><br><span class="line"> activity->callbacks->onStart = onStart;</span><br><span class="line"> activity->callbacks->onResume = onResume;</span><br><span class="line"> activity->callbacks->onSaveInstanceState = onSaveInstanceState;</span><br><span class="line"> activity->callbacks->onPause = onPause;</span><br><span class="line"> activity->callbacks->onStop = onStop;</span><br><span class="line"> activity->callbacks->onConfigurationChanged = onConfigurationChanged;</span><br><span class="line"> activity->callbacks->onLowMemory = onLowMemory;</span><br><span class="line"> activity->callbacks->onWindowFocusChanged = onWindowFocusChanged;</span><br><span class="line"> activity->callbacks->onNativeWindowCreated = onNativeWindowCreated;</span><br><span class="line"> activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed;</span><br><span class="line"> activity->callbacks->onInputQueueCreated = onInputQueueCreated;</span><br><span class="line"> activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;</span><br><span class="line"> activity->instance = android_app_create(activity, savedState, savedStateSize);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>android_native_app_glue.c中包含Activity的Native原生生命周期方法:</p>
<figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">onDestroy</span><span class="params">(ANativeActivity* activity)</span>;</span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">onStart</span><span class="params">(ANativeActivity* activity)</span>; </span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">onResume</span><span class="params">(ANativeActivity* activity)</span>;</span><br><span class="line">...</span><br></pre></td></tr></table></figure>
<p>在执行ANativeActivity_onCreate方法后,调用android_app_create方法,进入android_app_entry方法。android_app_entry调用main.cpp中我们写的android_main(android_app)。</p>
<figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="type">static</span> <span class="keyword">struct</span> android_app* <span class="title function_">android_app_create</span><span class="params">(ANativeActivity* activity,</span></span><br><span class="line"><span class="params"> <span class="type">void</span>* savedState, <span class="type">size_t</span> savedStateSize)</span> {</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">android_app</span>* <span class="title">android_app</span> =</span> (<span class="keyword">struct</span> android_app*)<span class="built_in">malloc</span>(<span class="keyword">sizeof</span>(<span class="keyword">struct</span> android_app));</span><br><span class="line"> <span class="built_in">memset</span>(android_app, <span class="number">0</span>, <span class="keyword">sizeof</span>(<span class="keyword">struct</span> android_app));</span><br><span class="line"> android_app->activity = activity;</span><br><span class="line"></span><br><span class="line"> pthread_mutex_init(&android_app->mutex, <span class="literal">NULL</span>);</span><br><span class="line"> pthread_cond_init(&android_app->cond, <span class="literal">NULL</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (savedState != <span class="literal">NULL</span>) {</span><br><span class="line"> android_app->savedState = <span class="built_in">malloc</span>(savedStateSize);</span><br><span class="line"> android_app->savedStateSize = savedStateSize;</span><br><span class="line"> <span class="built_in">memcpy</span>(android_app->savedState, savedState, savedStateSize);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="type">int</span> msgpipe[<span class="number">2</span>];</span><br><span class="line"> <span class="keyword">if</span> (pipe(msgpipe)) {</span><br><span class="line"> LOGE(<span class="string">"could not create pipe: %s"</span>, strerror(errno));</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line"> }</span><br><span class="line"> android_app->msgread = msgpipe[<span class="number">0</span>];</span><br><span class="line"> android_app->msgwrite = msgpipe[<span class="number">1</span>];</span><br><span class="line"></span><br><span class="line"> <span class="type">pthread_attr_t</span> attr; </span><br><span class="line"> pthread_attr_init(&attr);</span><br><span class="line"> pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);</span><br><span class="line"> pthread_create(&android_app->thread, &attr, android_app_entry, android_app);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Wait for thread to start.</span></span><br><span class="line"> pthread_mutex_lock(&android_app->mutex);</span><br><span class="line"> <span class="keyword">while</span> (!android_app->running) {</span><br><span class="line"> pthread_cond_wait(&android_app->cond, &android_app->mutex);</span><br><span class="line"> }</span><br><span class="line"> pthread_mutex_unlock(&android_app->mutex);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> android_app;</span><br><span class="line">}</span><br><span class="line"><span class="type">static</span> <span class="type">void</span>* <span class="title function_">android_app_entry</span><span class="params">(<span class="type">void</span>* param)</span> {</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">android_app</span>* <span class="title">android_app</span> =</span> (<span class="keyword">struct</span> android_app*)param;</span><br><span class="line"> android_app->config = AConfiguration_new();</span><br><span class="line"> AConfiguration_fromAssetManager(android_app->config, android_app->activity->assetManager);</span><br><span class="line"> print_cur_config(android_app);</span><br><span class="line"> android_app->cmdPollSource.id = LOOPER_ID_MAIN;</span><br><span class="line"> android_app->cmdPollSource.app = android_app;</span><br><span class="line"> android_app->cmdPollSource.process = process_cmd;</span><br><span class="line"> android_app->inputPollSource.id = LOOPER_ID_INPUT;</span><br><span class="line"> android_app->inputPollSource.app = android_app;</span><br><span class="line"> android_app->inputPollSource.process = process_input;</span><br><span class="line"> ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);</span><br><span class="line"> ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, <span class="literal">NULL</span>,</span><br><span class="line"> &android_app->cmdPollSource);</span><br><span class="line"> android_app->looper = looper;</span><br><span class="line"> pthread_mutex_lock(&android_app->mutex);</span><br><span class="line"> android_app->running = <span class="number">1</span>;</span><br><span class="line"> pthread_cond_broadcast(&android_app->cond);</span><br><span class="line"> pthread_mutex_unlock(&android_app->mutex);</span><br><span class="line"> android_main(android_app);</span><br><span class="line"> android_app_destroy(android_app);</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="0x03-NDK-Native-调用原理"><a href="#0x03-NDK-Native-调用原理" class="headerlink" title="0x03 NDK Native 调用原理"></a>0x03 NDK Native 调用原理</h3><p>我们来看一下NativeActivity加载NativeCode的过程。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">NativeActivity</span> <span class="keyword">extends</span> <span class="title class_">Activity</span> <span class="keyword">implements</span> <span class="title class_">SurfaceHolder</span>.Callback2,</span><br><span class="line"> InputQueue.Callback, OnGlobalLayoutListener{</span><br><span class="line"> <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">onCreate</span><span class="params">(Bundle savedInstanceState)</span> {</span><br><span class="line"> <span class="type">String</span> <span class="variable">libname</span> <span class="operator">=</span> <span class="string">"main"</span>;</span><br><span class="line"> <span class="type">String</span> <span class="variable">funcname</span> <span class="operator">=</span> <span class="string">"ANativeActivity_onCreate"</span>;</span><br><span class="line"> ActivityInfo ai;</span><br><span class="line"> mIMM = getSystemService(InputMethodManager.class);</span><br><span class="line"> getWindow().takeSurface(<span class="built_in">this</span>);</span><br><span class="line"> getWindow().takeInputQueue(<span class="built_in">this</span>);</span><br><span class="line"> getWindow().setFormat(PixelFormat.RGB_565);</span><br><span class="line"> getWindow().setSoftInputMode(</span><br><span class="line"> WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED</span><br><span class="line"> | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);</span><br><span class="line"> mNativeContentView = <span class="keyword">new</span> <span class="title class_">NativeContentView</span>(<span class="built_in">this</span>);</span><br><span class="line"> mNativeContentView.mActivity = <span class="built_in">this</span>;</span><br><span class="line"> setContentView(mNativeContentView);</span><br><span class="line"> mNativeContentView.requestFocus();</span><br><span class="line"> mNativeContentView.getViewTreeObserver().addOnGlobalLayoutListener(<span class="built_in">this</span>);</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> ai = getPackageManager().getActivityInfo(</span><br><span class="line"> getIntent().getComponent(), PackageManager.GET_META_DATA);</span><br><span class="line"> <span class="keyword">if</span> (ai.metaData != <span class="literal">null</span>) {</span><br><span class="line"> <span class="type">String</span> <span class="variable">ln</span> <span class="operator">=</span> ai.metaData.getString(META_DATA_LIB_NAME);</span><br><span class="line"> <span class="keyword">if</span> (ln != <span class="literal">null</span>) libname = ln;</span><br><span class="line"> ln = ai.metaData.getString(META_DATA_FUNC_NAME);</span><br><span class="line"> <span class="keyword">if</span> (ln != <span class="literal">null</span>) funcname = ln;</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">catch</span> (PackageManager.NameNotFoundException e) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">RuntimeException</span>(<span class="string">"Error getting activity info"</span>, e);</span><br><span class="line"> }</span><br><span class="line"> <span class="type">BaseDexClassLoader</span> <span class="variable">classLoader</span> <span class="operator">=</span> (BaseDexClassLoader) getClassLoader();</span><br><span class="line"> <span class="type">String</span> <span class="variable">path</span> <span class="operator">=</span> classLoader.findLibrary(libname);</span><br><span class="line"> <span class="keyword">if</span> (path == <span class="literal">null</span>) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalArgumentException</span>(<span class="string">"Unable to find native library "</span> + libname +</span><br><span class="line"> <span class="string">" using classloader: "</span> + classLoader.toString());</span><br><span class="line"> }</span><br><span class="line"> <span class="type">byte</span>[] nativeSavedState = savedInstanceState != <span class="literal">null</span></span><br><span class="line"> ? savedInstanceState.getByteArray(KEY_NATIVE_SAVED_STATE) : <span class="literal">null</span>;</span><br><span class="line"> mNativeHandle = loadNativeCode(path, funcname, Looper.myQueue(),</span><br><span class="line"> getAbsolutePath(getFilesDir()), getAbsolutePath(getObbDir()),</span><br><span class="line"> getAbsolutePath(getExternalFilesDir(<span class="literal">null</span>)),</span><br><span class="line"> Build.VERSION.SDK_INT, getAssets(), nativeSavedState,</span><br><span class="line"> classLoader, classLoader.getLdLibraryPath());</span><br><span class="line"> <span class="keyword">if</span> (mNativeHandle == <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">UnsatisfiedLinkError</span>(</span><br><span class="line"> <span class="string">"Unable to load native library \""</span> + path + <span class="string">"\": "</span> + getDlError());</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">super</span>.onCreate(savedInstanceState);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>onCreate方法中主要实现了以下功能:</p>
<ol>
<li>托管Surface、InputQueue给Native</li>
<li>设置 NativeContentView</li>
<li>加载so库,获取mNativeHandle</li>
</ol>
<p>在onStart、onResume、onPause、onStop等中分别调用Native方法,在onDestroy总则注销Surface、InputQueue以及unloadNativeCode。</p>
<p>其中libname默认为main,funcname默认为ANativeActivity_onCreate。libname即为加载的Native库的名称:</p>
<figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"> <span class="tag"><<span class="name">application</span> <span class="attr">android:label</span>=<span class="string">"@string/app_name"</span> <span class="attr">android:hasCode</span>=<span class="string">"false"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">activity</span> <span class="attr">android:name</span>=<span class="string">"android.app.NativeActivity"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">android:label</span>=<span class="string">"@string/app_name"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">meta-data</span> <span class="attr">android:name</span>=<span class="string">"android.app.lib_name"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">android:value</span>=<span class="string">"main"</span>/></span></span><br><span class="line"> <span class="tag"><<span class="name">intent-filter</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">action</span> <span class="attr">android:name</span>=<span class="string">"android.intent.action.MAIN"</span>/></span></span><br><span class="line"> <span class="tag"><<span class="name">category</span> <span class="attr">android:name</span>=<span class="string">"android.intent.category.LAUNCHER"</span>/></span></span><br><span class="line"> <span class="tag"></<span class="name">intent-filter</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">activity</span>></span></span><br><span class="line"><span class="tag"></<span class="name">application</span>></span></span><br></pre></td></tr></table></figure>
<p>对应<code>android.app.lib_name</code> 的值<code>main</code> ,而funcname对于Native中loadNativeCode_native时的createActivityFunc,用于创建Activity。这2个名字可根据实际情况自定义。</p>
<p>在/<a href="http://androidxref.com/9.0.0_r3/xref/frameworks/">frameworks</a>/<a href="http://androidxref.com/9.0.0_r3/xref/frameworks/base/">base</a>/<a href="http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/">core</a>/<a href="http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/jni/">jni</a>/<a href="http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/jni/android_app_NativeActivity.cpp">android_app_NativeActivity.cpp</a> 中我们可以看到Native方法的具体实现:</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="type">static</span> jlong</span></span><br><span class="line"><span class="function"><span class="title">loadNativeCode_native</span><span class="params">(JNIEnv* env, jobject clazz, jstring path, jstring funcName,</span></span></span><br><span class="line"><span class="params"><span class="function"> jobject messageQueue, jstring internalDataDir, jstring obbDir,</span></span></span><br><span class="line"><span class="params"><span class="function"> jstring externalDataDir, jint sdkVersion, jobject jAssetMgr,</span></span></span><br><span class="line"><span class="params"><span class="function"> jbyteArray savedState, jobject classLoader, jstring libraryPath)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (kLogTrace) {</span><br><span class="line"> <span class="built_in">ALOGD</span>(<span class="string">"loadNativeCode_native"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function">ScopedUtfChars <span class="title">pathStr</span><span class="params">(env, path)</span></span>;</span><br><span class="line"> std::unique_ptr<NativeCode> code;</span><br><span class="line"> <span class="type">bool</span> needs_native_bridge = <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line"> <span class="type">void</span>* handle = <span class="built_in">OpenNativeLibrary</span>(env,</span><br><span class="line"> sdkVersion,</span><br><span class="line"> pathStr.<span class="built_in">c_str</span>(),</span><br><span class="line"> classLoader,</span><br><span class="line"> libraryPath,</span><br><span class="line"> &needs_native_bridge,</span><br><span class="line"> &g_error_msg);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (handle == <span class="literal">nullptr</span>) {</span><br><span class="line"> <span class="built_in">ALOGW</span>(<span class="string">"NativeActivity LoadNativeLibrary(\"%s\") failed: %s"</span>,</span><br><span class="line"> pathStr.<span class="built_in">c_str</span>(),</span><br><span class="line"> g_error_msg.<span class="built_in">c_str</span>());</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="type">void</span>* funcPtr = <span class="literal">NULL</span>;</span><br><span class="line"> <span class="type">const</span> <span class="type">char</span>* funcStr = env-><span class="built_in">GetStringUTFChars</span>(funcName, <span class="literal">NULL</span>);</span><br><span class="line"> <span class="keyword">if</span> (needs_native_bridge) {</span><br><span class="line"> funcPtr = <span class="built_in">NativeBridgeGetTrampoline</span>(handle, funcStr, <span class="literal">NULL</span>, <span class="number">0</span>);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> funcPtr = <span class="built_in">dlsym</span>(handle, funcStr);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> code.<span class="built_in">reset</span>(<span class="keyword">new</span> <span class="built_in">NativeCode</span>(handle, (ANativeActivity_createFunc*)funcPtr));</span><br><span class="line"> env-><span class="built_in">ReleaseStringUTFChars</span>(funcName, funcStr);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (code->createActivityFunc == <span class="literal">NULL</span>) {</span><br><span class="line"> g_error_msg = needs_native_bridge ? <span class="built_in">NativeBridgeGetError</span>() : <span class="built_in">dlerror</span>();</span><br><span class="line"> <span class="built_in">ALOGW</span>(<span class="string">"ANativeActivity_onCreate not found: %s"</span>, g_error_msg.<span class="built_in">c_str</span>());</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> code->messageQueue = <span class="built_in">android_os_MessageQueue_getMessageQueue</span>(env, messageQueue);</span><br><span class="line"> <span class="keyword">if</span> (code->messageQueue == <span class="literal">NULL</span>) {</span><br><span class="line"> g_error_msg = <span class="string">"Unable to retrieve native MessageQueue"</span>;</span><br><span class="line"> <span class="built_in">ALOGW</span>(<span class="string">"%s"</span>, g_error_msg.<span class="built_in">c_str</span>());</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="type">int</span> msgpipe[<span class="number">2</span>];</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">pipe</span>(msgpipe)) {</span><br><span class="line"> g_error_msg = android::base::<span class="built_in">StringPrintf</span>(<span class="string">"could not create pipe: %s"</span>, <span class="built_in">strerror</span>(errno));</span><br><span class="line"> <span class="built_in">ALOGW</span>(<span class="string">"%s"</span>, g_error_msg.<span class="built_in">c_str</span>());</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> code->mainWorkRead = msgpipe[<span class="number">0</span>];</span><br><span class="line"> code->mainWorkWrite = msgpipe[<span class="number">1</span>];</span><br><span class="line"> <span class="type">int</span> result = <span class="built_in">fcntl</span>(code->mainWorkRead, F_SETFL, O_NONBLOCK);</span><br><span class="line"> <span class="built_in">SLOGW_IF</span>(result != <span class="number">0</span>, <span class="string">"Could not make main work read pipe "</span></span><br><span class="line"> <span class="string">"non-blocking: %s"</span>, <span class="built_in">strerror</span>(errno));</span><br><span class="line"> result = <span class="built_in">fcntl</span>(code->mainWorkWrite, F_SETFL, O_NONBLOCK);</span><br><span class="line"> <span class="built_in">SLOGW_IF</span>(result != <span class="number">0</span>, <span class="string">"Could not make main work write pipe "</span></span><br><span class="line"> <span class="string">"non-blocking: %s"</span>, <span class="built_in">strerror</span>(errno));</span><br><span class="line"> code->messageQueue-><span class="built_in">getLooper</span>()-><span class="built_in">addFd</span>(</span><br><span class="line"> code->mainWorkRead, <span class="number">0</span>, ALOOPER_EVENT_INPUT, mainWorkCallback, code.<span class="built_in">get</span>());</span><br><span class="line"></span><br><span class="line"> code->ANativeActivity::callbacks = &code->callbacks;</span><br><span class="line"> <span class="keyword">if</span> (env-><span class="built_in">GetJavaVM</span>(&code->vm) < <span class="number">0</span>) {</span><br><span class="line"> g_error_msg = <span class="string">"NativeActivity GetJavaVM failed"</span>;</span><br><span class="line"> <span class="built_in">ALOGW</span>(<span class="string">"%s"</span>, g_error_msg.<span class="built_in">c_str</span>());</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> code->env = env;</span><br><span class="line"> code->clazz = env-><span class="built_in">NewGlobalRef</span>(clazz);</span><br><span class="line"></span><br><span class="line"> <span class="type">const</span> <span class="type">char</span>* dirStr = env-><span class="built_in">GetStringUTFChars</span>(internalDataDir, <span class="literal">NULL</span>);</span><br><span class="line"> code->internalDataPathObj = dirStr;</span><br><span class="line"> code->internalDataPath = code->internalDataPathObj.<span class="built_in">string</span>();</span><br><span class="line"> env-><span class="built_in">ReleaseStringUTFChars</span>(internalDataDir, dirStr);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (externalDataDir != <span class="literal">NULL</span>) {</span><br><span class="line"> dirStr = env-><span class="built_in">GetStringUTFChars</span>(externalDataDir, <span class="literal">NULL</span>);</span><br><span class="line"> code->externalDataPathObj = dirStr;</span><br><span class="line"> env-><span class="built_in">ReleaseStringUTFChars</span>(externalDataDir, dirStr);</span><br><span class="line"> }</span><br><span class="line"> code->externalDataPath = code->externalDataPathObj.<span class="built_in">string</span>();</span><br><span class="line"></span><br><span class="line"> code->sdkVersion = sdkVersion;</span><br><span class="line"></span><br><span class="line"> code->javaAssetManager = env-><span class="built_in">NewGlobalRef</span>(jAssetMgr);</span><br><span class="line"> code->assetManager = <span class="built_in">NdkAssetManagerForJavaObject</span>(env, jAssetMgr);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (obbDir != <span class="literal">NULL</span>) {</span><br><span class="line"> dirStr = env-><span class="built_in">GetStringUTFChars</span>(obbDir, <span class="literal">NULL</span>);</span><br><span class="line"> code->obbPathObj = dirStr;</span><br><span class="line"> env-><span class="built_in">ReleaseStringUTFChars</span>(obbDir, dirStr);</span><br><span class="line"> }</span><br><span class="line"> code->obbPath = code->obbPathObj.<span class="built_in">string</span>();</span><br><span class="line"></span><br><span class="line"> jbyte* rawSavedState = <span class="literal">NULL</span>;</span><br><span class="line"> jsize rawSavedSize = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">if</span> (savedState != <span class="literal">NULL</span>) {</span><br><span class="line"> rawSavedState = env-><span class="built_in">GetByteArrayElements</span>(savedState, <span class="literal">NULL</span>);</span><br><span class="line"> rawSavedSize = env-><span class="built_in">GetArrayLength</span>(savedState);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> code-><span class="built_in">createActivityFunc</span>(code.<span class="built_in">get</span>(), rawSavedState, rawSavedSize);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (rawSavedState != <span class="literal">NULL</span>) {</span><br><span class="line"> env-><span class="built_in">ReleaseByteArrayElements</span>(savedState, rawSavedState, <span class="number">0</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> (jlong)code.<span class="built_in">release</span>();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">static</span> jstring <span class="title">getDlError_native</span><span class="params">(JNIEnv* env, jobject clazz)</span> </span>{</span><br><span class="line"> jstring result = env-><span class="built_in">NewStringUTF</span>(g_error_msg.<span class="built_in">c_str</span>());</span><br><span class="line"> g_error_msg.<span class="built_in">clear</span>();</span><br><span class="line"> <span class="keyword">return</span> result;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">static</span> <span class="type">void</span></span></span><br><span class="line"><span class="function"><span class="title">unloadNativeCode_native</span><span class="params">(JNIEnv* env, jobject clazz, jlong handle)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (kLogTrace) {</span><br><span class="line"> <span class="built_in">ALOGD</span>(<span class="string">"unloadNativeCode_native"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (handle != <span class="number">0</span>) {</span><br><span class="line"> NativeCode* code = (NativeCode*)handle;</span><br><span class="line"> <span class="keyword">delete</span> code;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">static</span> <span class="type">void</span></span></span><br><span class="line"><span class="function"><span class="title">onStart_native</span><span class="params">(JNIEnv* env, jobject clazz, jlong handle)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (kLogTrace) {</span><br><span class="line"> <span class="built_in">ALOGD</span>(<span class="string">"onStart_native"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (handle != <span class="number">0</span>) {</span><br><span class="line"> NativeCode* code = (NativeCode*)handle;</span><br><span class="line"> <span class="keyword">if</span> (code->callbacks.onStart != <span class="literal">NULL</span>) {</span><br><span class="line"> code->callbacks.<span class="built_in">onStart</span>(code);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">static</span> <span class="type">void</span></span></span><br><span class="line"><span class="function"><span class="title">onResume_native</span><span class="params">(JNIEnv* env, jobject clazz, jlong handle)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (kLogTrace) {</span><br><span class="line"> <span class="built_in">ALOGD</span>(<span class="string">"onResume_native"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (handle != <span class="number">0</span>) {</span><br><span class="line"> NativeCode* code = (NativeCode*)handle;</span><br><span class="line"> <span class="keyword">if</span> (code->callbacks.onResume != <span class="literal">NULL</span>) {</span><br><span class="line"> code->callbacks.<span class="built_in">onResume</span>(code);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">static</span> jbyteArray</span></span><br><span class="line"><span class="function"><span class="title">onSaveInstanceState_native</span><span class="params">(JNIEnv* env, jobject clazz, jlong handle)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (kLogTrace) {</span><br><span class="line"> <span class="built_in">ALOGD</span>(<span class="string">"onSaveInstanceState_native"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> jbyteArray array = <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (handle != <span class="number">0</span>) {</span><br><span class="line"> NativeCode* code = (NativeCode*)handle;</span><br><span class="line"> <span class="keyword">if</span> (code->callbacks.onSaveInstanceState != <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="type">size_t</span> len = <span class="number">0</span>;</span><br><span class="line"> jbyte* state = (jbyte*)code->callbacks.<span class="built_in">onSaveInstanceState</span>(code, &len);</span><br><span class="line"> <span class="keyword">if</span> (len > <span class="number">0</span>) {</span><br><span class="line"> array = env-><span class="built_in">NewByteArray</span>(len);</span><br><span class="line"> <span class="keyword">if</span> (array != <span class="literal">NULL</span>) {</span><br><span class="line"> env-><span class="built_in">SetByteArrayRegion</span>(array, <span class="number">0</span>, len, state);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (state != <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="built_in">free</span>(state);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> array;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">static</span> <span class="type">void</span></span></span><br><span class="line"><span class="function"><span class="title">onPause_native</span><span class="params">(JNIEnv* env, jobject clazz, jlong handle)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (kLogTrace) {</span><br><span class="line"> <span class="built_in">ALOGD</span>(<span class="string">"onPause_native"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (handle != <span class="number">0</span>) {</span><br><span class="line"> NativeCode* code = (NativeCode*)handle;</span><br><span class="line"> <span class="keyword">if</span> (code->callbacks.onPause != <span class="literal">NULL</span>) {</span><br><span class="line"> code->callbacks.<span class="built_in">onPause</span>(code);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">static</span> <span class="type">void</span></span></span><br><span class="line"><span class="function"><span class="title">onStop_native</span><span class="params">(JNIEnv* env, jobject clazz, jlong handle)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (kLogTrace) {</span><br><span class="line"> <span class="built_in">ALOGD</span>(<span class="string">"onStop_native"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (handle != <span class="number">0</span>) {</span><br><span class="line"> NativeCode* code = (NativeCode*)handle;</span><br><span class="line"> <span class="keyword">if</span> (code->callbacks.onStop != <span class="literal">NULL</span>) {</span><br><span class="line"> code->callbacks.<span class="built_in">onStop</span>(code);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">static</span> <span class="type">void</span></span></span><br><span class="line"><span class="function"><span class="title">onConfigurationChanged_native</span><span class="params">(JNIEnv* env, jobject clazz, jlong handle)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (kLogTrace) {</span><br><span class="line"> <span class="built_in">ALOGD</span>(<span class="string">"onConfigurationChanged_native"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (handle != <span class="number">0</span>) {</span><br><span class="line"> NativeCode* code = (NativeCode*)handle;</span><br><span class="line"> <span class="keyword">if</span> (code->callbacks.onConfigurationChanged != <span class="literal">NULL</span>) {</span><br><span class="line"> code->callbacks.<span class="built_in">onConfigurationChanged</span>(code);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">static</span> <span class="type">void</span></span></span><br><span class="line"><span class="function"><span class="title">onLowMemory_native</span><span class="params">(JNIEnv* env, jobject clazz, jlong handle)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (kLogTrace) {</span><br><span class="line"> <span class="built_in">ALOGD</span>(<span class="string">"onLowMemory_native"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (handle != <span class="number">0</span>) {</span><br><span class="line"> NativeCode* code = (NativeCode*)handle;</span><br><span class="line"> <span class="keyword">if</span> (code->callbacks.onLowMemory != <span class="literal">NULL</span>) {</span><br><span class="line"> code->callbacks.<span class="built_in">onLowMemory</span>(code);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">static</span> <span class="type">void</span></span></span><br><span class="line"><span class="function"><span class="title">onWindowFocusChanged_native</span><span class="params">(JNIEnv* env, jobject clazz, jlong handle, jboolean focused)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (kLogTrace) {</span><br><span class="line"> <span class="built_in">ALOGD</span>(<span class="string">"onWindowFocusChanged_native"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (handle != <span class="number">0</span>) {</span><br><span class="line"> NativeCode* code = (NativeCode*)handle;</span><br><span class="line"> <span class="keyword">if</span> (code->callbacks.onWindowFocusChanged != <span class="literal">NULL</span>) {</span><br><span class="line"> code->callbacks.<span class="built_in">onWindowFocusChanged</span>(code, focused ? <span class="number">1</span> : <span class="number">0</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">static</span> <span class="type">void</span></span></span><br><span class="line"><span class="function"><span class="title">onSurfaceCreated_native</span><span class="params">(JNIEnv* env, jobject clazz, jlong handle, jobject surface)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (kLogTrace) {</span><br><span class="line"> <span class="built_in">ALOGD</span>(<span class="string">"onSurfaceCreated_native"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (handle != <span class="number">0</span>) {</span><br><span class="line"> NativeCode* code = (NativeCode*)handle;</span><br><span class="line"> code-><span class="built_in">setSurface</span>(surface);</span><br><span class="line"> <span class="keyword">if</span> (code->nativeWindow != <span class="literal">NULL</span> && code->callbacks.onNativeWindowCreated != <span class="literal">NULL</span>) {</span><br><span class="line"> code->callbacks.<span class="built_in">onNativeWindowCreated</span>(code,</span><br><span class="line"> code->nativeWindow.<span class="built_in">get</span>());</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">static</span> <span class="type">int32_t</span> <span class="title">getWindowProp</span><span class="params">(ANativeWindow* window, <span class="type">int</span> what)</span> </span>{</span><br><span class="line"> <span class="type">int</span> value;</span><br><span class="line"> <span class="type">int</span> res = window-><span class="built_in">query</span>(window, what, &value);</span><br><span class="line"> <span class="keyword">return</span> res < <span class="number">0</span> ? res : value;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">static</span> <span class="type">void</span></span></span><br><span class="line"><span class="function"><span class="title">onSurfaceChanged_native</span><span class="params">(JNIEnv* env, jobject clazz, jlong handle, jobject surface,</span></span></span><br><span class="line"><span class="params"><span class="function"> jint format, jint width, jint height)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (kLogTrace) {</span><br><span class="line"> <span class="built_in">ALOGD</span>(<span class="string">"onSurfaceChanged_native"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (handle != <span class="number">0</span>) {</span><br><span class="line"> NativeCode* code = (NativeCode*)handle;</span><br><span class="line"> sp<ANativeWindow> oldNativeWindow = code->nativeWindow;</span><br><span class="line"> code-><span class="built_in">setSurface</span>(surface);</span><br><span class="line"> <span class="keyword">if</span> (oldNativeWindow != code->nativeWindow) {</span><br><span class="line"> <span class="keyword">if</span> (oldNativeWindow != <span class="literal">NULL</span> && code->callbacks.onNativeWindowDestroyed != <span class="literal">NULL</span>) {</span><br><span class="line"> code->callbacks.<span class="built_in">onNativeWindowDestroyed</span>(code,</span><br><span class="line"> oldNativeWindow.<span class="built_in">get</span>());</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (code->nativeWindow != <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">if</span> (code->callbacks.onNativeWindowCreated != <span class="literal">NULL</span>) {</span><br><span class="line"> code->callbacks.<span class="built_in">onNativeWindowCreated</span>(code,</span><br><span class="line"> code->nativeWindow.<span class="built_in">get</span>());</span><br><span class="line"> }</span><br><span class="line"> code->lastWindowWidth = <span class="built_in">getWindowProp</span>(code->nativeWindow.<span class="built_in">get</span>(),</span><br><span class="line"> NATIVE_WINDOW_WIDTH);</span><br><span class="line"> code->lastWindowHeight = <span class="built_in">getWindowProp</span>(code->nativeWindow.<span class="built_in">get</span>(),</span><br><span class="line"> NATIVE_WINDOW_HEIGHT);</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">// Maybe it resized?</span></span><br><span class="line"> <span class="type">int32_t</span> newWidth = <span class="built_in">getWindowProp</span>(code->nativeWindow.<span class="built_in">get</span>(),</span><br><span class="line"> NATIVE_WINDOW_WIDTH);</span><br><span class="line"> <span class="type">int32_t</span> newHeight = <span class="built_in">getWindowProp</span>(code->nativeWindow.<span class="built_in">get</span>(),</span><br><span class="line"> NATIVE_WINDOW_HEIGHT);</span><br><span class="line"> <span class="keyword">if</span> (newWidth != code->lastWindowWidth</span><br><span class="line"> || newHeight != code->lastWindowHeight) {</span><br><span class="line"> <span class="keyword">if</span> (code->callbacks.onNativeWindowResized != <span class="literal">NULL</span>) {</span><br><span class="line"> code->callbacks.<span class="built_in">onNativeWindowResized</span>(code,</span><br><span class="line"> code->nativeWindow.<span class="built_in">get</span>());</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">static</span> <span class="type">void</span></span></span><br><span class="line"><span class="function"><span class="title">onSurfaceRedrawNeeded_native</span><span class="params">(JNIEnv* env, jobject clazz, jlong handle)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (kLogTrace) {</span><br><span class="line"> <span class="built_in">ALOGD</span>(<span class="string">"onSurfaceRedrawNeeded_native"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (handle != <span class="number">0</span>) {</span><br><span class="line"> NativeCode* code = (NativeCode*)handle;</span><br><span class="line"> <span class="keyword">if</span> (code->nativeWindow != <span class="literal">NULL</span> && code->callbacks.onNativeWindowRedrawNeeded != <span class="literal">NULL</span>) {</span><br><span class="line"> code->callbacks.<span class="built_in">onNativeWindowRedrawNeeded</span>(code, code->nativeWindow.<span class="built_in">get</span>());</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">static</span> <span class="type">void</span></span></span><br><span class="line"><span class="function"><span class="title">onSurfaceDestroyed_native</span><span class="params">(JNIEnv* env, jobject clazz, jlong handle, jobject surface)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (kLogTrace) {</span><br><span class="line"> <span class="built_in">ALOGD</span>(<span class="string">"onSurfaceDestroyed_native"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (handle != <span class="number">0</span>) {</span><br><span class="line"> NativeCode* code = (NativeCode*)handle;</span><br><span class="line"> <span class="keyword">if</span> (code->nativeWindow != <span class="literal">NULL</span> && code->callbacks.onNativeWindowDestroyed != <span class="literal">NULL</span>) {</span><br><span class="line"> code->callbacks.<span class="built_in">onNativeWindowDestroyed</span>(code,</span><br><span class="line"> code->nativeWindow.<span class="built_in">get</span>());</span><br><span class="line"> }</span><br><span class="line"> code-><span class="built_in">setSurface</span>(<span class="literal">NULL</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">static</span> <span class="type">void</span></span></span><br><span class="line"><span class="function"><span class="title">onInputQueueCreated_native</span><span class="params">(JNIEnv* env, jobject clazz, jlong handle, jlong queuePtr)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (kLogTrace) {</span><br><span class="line"> <span class="built_in">ALOGD</span>(<span class="string">"onInputChannelCreated_native"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (handle != <span class="number">0</span>) {</span><br><span class="line"> NativeCode* code = (NativeCode*)handle;</span><br><span class="line"> <span class="keyword">if</span> (code->callbacks.onInputQueueCreated != <span class="literal">NULL</span>) {</span><br><span class="line"> AInputQueue* queue = <span class="built_in">reinterpret_cast</span><AInputQueue*>(queuePtr);</span><br><span class="line"> code->callbacks.<span class="built_in">onInputQueueCreated</span>(code, queue);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">static</span> <span class="type">void</span></span></span><br><span class="line"><span class="function"><span class="title">onInputQueueDestroyed_native</span><span class="params">(JNIEnv* env, jobject clazz, jlong handle, jlong queuePtr)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (kLogTrace) {</span><br><span class="line"> <span class="built_in">ALOGD</span>(<span class="string">"onInputChannelDestroyed_native"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (handle != <span class="number">0</span>) {</span><br><span class="line"> NativeCode* code = (NativeCode*)handle;</span><br><span class="line"> <span class="keyword">if</span> (code->callbacks.onInputQueueDestroyed != <span class="literal">NULL</span>) {</span><br><span class="line"> AInputQueue* queue = <span class="built_in">reinterpret_cast</span><AInputQueue*>(queuePtr);</span><br><span class="line"> code->callbacks.<span class="built_in">onInputQueueDestroyed</span>(code, queue);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">static</span> <span class="type">void</span></span></span><br><span class="line"><span class="function"><span class="title">onContentRectChanged_native</span><span class="params">(JNIEnv* env, jobject clazz, jlong handle,</span></span></span><br><span class="line"><span class="params"><span class="function"> jint x, jint y, jint w, jint h)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (kLogTrace) {</span><br><span class="line"> <span class="built_in">ALOGD</span>(<span class="string">"onContentRectChanged_native"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (handle != <span class="number">0</span>) {</span><br><span class="line"> NativeCode* code = (NativeCode*)handle;</span><br><span class="line"> <span class="keyword">if</span> (code->callbacks.onContentRectChanged != <span class="literal">NULL</span>) {</span><br><span class="line"> ARect rect;</span><br><span class="line"> rect.left = x;</span><br><span class="line"> rect.top = y;</span><br><span class="line"> rect.right = x+w;</span><br><span class="line"> rect.bottom = y+h;</span><br><span class="line"> code->callbacks.<span class="built_in">onContentRectChanged</span>(code, &rect);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">const</span> JNINativeMethod g_methods[] = {</span><br><span class="line"> { <span class="string">"loadNativeCode"</span>,</span><br><span class="line"> <span class="string">"(Ljava/lang/String;Ljava/lang/String;Landroid/os/MessageQueue;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILandroid/content/res/AssetManager;[BLjava/lang/ClassLoader;Ljava/lang/String;)J"</span>,</span><br><span class="line"> (<span class="type">void</span>*)loadNativeCode_native },</span><br><span class="line"> { <span class="string">"getDlError"</span>, <span class="string">"()Ljava/lang/String;"</span>, (<span class="type">void</span>*) getDlError_native },</span><br><span class="line"> { <span class="string">"unloadNativeCode"</span>, <span class="string">"(J)V"</span>, (<span class="type">void</span>*)unloadNativeCode_native },</span><br><span class="line"> { <span class="string">"onStartNative"</span>, <span class="string">"(J)V"</span>, (<span class="type">void</span>*)onStart_native },</span><br><span class="line"> { <span class="string">"onResumeNative"</span>, <span class="string">"(J)V"</span>, (<span class="type">void</span>*)onResume_native },</span><br><span class="line"> { <span class="string">"onSaveInstanceStateNative"</span>, <span class="string">"(J)[B"</span>, (<span class="type">void</span>*)onSaveInstanceState_native },</span><br><span class="line"> { <span class="string">"onPauseNative"</span>, <span class="string">"(J)V"</span>, (<span class="type">void</span>*)onPause_native },</span><br><span class="line"> { <span class="string">"onStopNative"</span>, <span class="string">"(J)V"</span>, (<span class="type">void</span>*)onStop_native },</span><br><span class="line"> { <span class="string">"onConfigurationChangedNative"</span>, <span class="string">"(J)V"</span>, (<span class="type">void</span>*)onConfigurationChanged_native },</span><br><span class="line"> { <span class="string">"onLowMemoryNative"</span>, <span class="string">"(J)V"</span>, (<span class="type">void</span>*)onLowMemory_native },</span><br><span class="line"> { <span class="string">"onWindowFocusChangedNative"</span>, <span class="string">"(JZ)V"</span>, (<span class="type">void</span>*)onWindowFocusChanged_native },</span><br><span class="line"> { <span class="string">"onSurfaceCreatedNative"</span>, <span class="string">"(JLandroid/view/Surface;)V"</span>, (<span class="type">void</span>*)onSurfaceCreated_native },</span><br><span class="line"> { <span class="string">"onSurfaceChangedNative"</span>, <span class="string">"(JLandroid/view/Surface;III)V"</span>, (<span class="type">void</span>*)onSurfaceChanged_native },</span><br><span class="line"> { <span class="string">"onSurfaceRedrawNeededNative"</span>, <span class="string">"(JLandroid/view/Surface;)V"</span>, (<span class="type">void</span>*)onSurfaceRedrawNeeded_native },</span><br><span class="line"> { <span class="string">"onSurfaceDestroyedNative"</span>, <span class="string">"(J)V"</span>, (<span class="type">void</span>*)onSurfaceDestroyed_native },</span><br><span class="line"> { <span class="string">"onInputQueueCreatedNative"</span>, <span class="string">"(JJ)V"</span>,</span><br><span class="line"> (<span class="type">void</span>*)onInputQueueCreated_native },</span><br><span class="line"> { <span class="string">"onInputQueueDestroyedNative"</span>, <span class="string">"(JJ)V"</span>,</span><br><span class="line"> (<span class="type">void</span>*)onInputQueueDestroyed_native },</span><br><span class="line"> { <span class="string">"onContentRectChangedNative"</span>, <span class="string">"(JIIII)V"</span>, (<span class="type">void</span>*)onContentRectChanged_native },</span><br><span class="line">};</span><br></pre></td></tr></table></figure>
<p>loadNativeCode_native加载Native库,获取handle,在Activity生命周期中,生命周期方法通过NativeCode* code = (NativeCode*)handle; 交由Native代码执行,上文中直接使用 <a href="http://androidxref.com/9.0.0_r3/xref/prebuilts/ndk/current/sources/android/native_app_glue/android_native_app_glue.c">android_native_app_glue.c</a> , 里面已经实现了Native生命周期方法,也可自己写。</p>
<p>在loadNativeCode_native时:</p>
<ol>
<li><p>首先是通过OpenNativeLibrary来获取handle</p>
</li>
<li><p>通过设定的funcname来获取Activity创建方法 createActivityFunc</p>
</li>
<li><p>设置messageQueue</p>
</li>
<li><p>在messageQueue中设置主进程回调</p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line">code->messageQueue-><span class="built_in">getLooper</span>()-><span class="built_in">addFd</span>(</span><br><span class="line"> code->mainWorkRead, <span class="number">0</span>, ALOOPER_EVENT_INPUT, mainWorkCallback, code.<span class="built_in">get</span>());</span><br></pre></td></tr></table></figure>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="type">static</span> <span class="type">int</span> <span class="title">mainWorkCallback</span><span class="params">(<span class="type">int</span> fd, <span class="type">int</span> events, <span class="type">void</span>* data)</span> </span>{</span><br><span class="line"> NativeCode* code = (NativeCode*)data;</span><br><span class="line"> <span class="keyword">if</span> ((events & POLLIN) == <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> ActivityWork work;</span><br><span class="line"> <span class="keyword">if</span> (!<span class="built_in">read_work</span>(code->mainWorkRead, &work)) {</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (kLogTrace) {</span><br><span class="line"> <span class="built_in">ALOGD</span>(<span class="string">"mainWorkCallback: cmd=%d"</span>, work.cmd);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">switch</span> (work.cmd) {</span><br><span class="line"> <span class="keyword">case</span> CMD_FINISH: {</span><br><span class="line"> code->env-><span class="built_in">CallVoidMethod</span>(code->clazz, gNativeActivityClassInfo.finish);</span><br><span class="line"> code->messageQueue-><span class="built_in">raiseAndClearException</span>(code->env, <span class="string">"finish"</span>);</span><br><span class="line"> } <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> CMD_SET_WINDOW_FORMAT: {</span><br><span class="line"> code->env-><span class="built_in">CallVoidMethod</span>(code->clazz,</span><br><span class="line"> gNativeActivityClassInfo.setWindowFormat, work.arg1);</span><br><span class="line"> code->messageQueue-><span class="built_in">raiseAndClearException</span>(code->env, <span class="string">"setWindowFormat"</span>);</span><br><span class="line"> } <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> CMD_SET_WINDOW_FLAGS: {</span><br><span class="line"> code->env-><span class="built_in">CallVoidMethod</span>(code->clazz,</span><br><span class="line"> gNativeActivityClassInfo.setWindowFlags, work.arg1, work.arg2);</span><br><span class="line"> code->messageQueue-><span class="built_in">raiseAndClearException</span>(code->env, <span class="string">"setWindowFlags"</span>);</span><br><span class="line"> } <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> CMD_SHOW_SOFT_INPUT: {</span><br><span class="line"> code->env-><span class="built_in">CallVoidMethod</span>(code->clazz,</span><br><span class="line"> gNativeActivityClassInfo.showIme, work.arg1);</span><br><span class="line"> code->messageQueue-><span class="built_in">raiseAndClearException</span>(code->env, <span class="string">"showIme"</span>);</span><br><span class="line"> } <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> CMD_HIDE_SOFT_INPUT: {</span><br><span class="line"> code->env-><span class="built_in">CallVoidMethod</span>(code->clazz,</span><br><span class="line"> gNativeActivityClassInfo.hideIme, work.arg1);</span><br><span class="line"> code->messageQueue-><span class="built_in">raiseAndClearException</span>(code->env, <span class="string">"hideIme"</span>);</span><br><span class="line"> } <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">default</span>:</span><br><span class="line"> <span class="built_in">ALOGW</span>(<span class="string">"Unknown work command: %d"</span>, work.cmd);</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>getLooper()->addFd() 方法见: /<a href="http://androidxref.com/9.0.0_r3/xref/system/">system</a>/<a href="http://androidxref.com/9.0.0_r3/xref/system/core/">core</a>/<a href="http://androidxref.com/9.0.0_r3/xref/system/core/libutils/">libutils</a>/<a href="http://androidxref.com/9.0.0_r3/xref/system/core/libutils/Looper.cpp">Looper.cpp</a></p>
<p>数据通信通过管道进行。</p>
</li>
<li><p>设置JavaVM给NativeCode</p>
</li>
<li><p>设置internalDataPath、externalDataPath、javaAssetManager、obbPath</p>
</li>
<li><p>获取rawSavedState,并执行createActivityFunc</p>
</li>
<li><p>释放资源</p>
</li>
</ol>
<p>至此,完成Activity创建。</p>
<p>可简单看一下OpenNativeLibrary代码,OpenNativeLibrary方法也是Android加载JNI库时,实际使用的方法:</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">System.loadLibrary(<span class="string">"native-lib"</span>);</span><br></pre></td></tr></table></figure>
<p>/<a href="http://androidxref.com/9.0.0_r3/xref/system/">system</a>/<a href="http://androidxref.com/9.0.0_r3/xref/system/core/">core</a>/<a href="http://androidxref.com/9.0.0_r3/xref/system/core/libnativeloader/">libnativeloader</a>/<a href="http://androidxref.com/9.0.0_r3/xref/system/core/libnativeloader/native_loader.cpp">native_loader.cpp</a></p>
<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span>* <span class="title">OpenNativeLibrary</span><span class="params">(JNIEnv* env,</span></span></span><br><span class="line"><span class="params"><span class="function"> <span class="type">int32_t</span> target_sdk_version,</span></span></span><br><span class="line"><span class="params"><span class="function"> <span class="type">const</span> <span class="type">char</span>* path,</span></span></span><br><span class="line"><span class="params"><span class="function"> jobject class_loader,</span></span></span><br><span class="line"><span class="params"><span class="function"> jstring library_path,</span></span></span><br><span class="line"><span class="params"><span class="function"> <span class="type">bool</span>* needs_native_bridge,</span></span></span><br><span class="line"><span class="params"><span class="function"> std::string* error_msg)</span> </span>{</span><br><span class="line"><span class="meta">#<span class="keyword">if</span> defined(__ANDROID__)</span></span><br><span class="line"> <span class="built_in">UNUSED</span>(target_sdk_version);</span><br><span class="line"> <span class="keyword">if</span> (class_loader == <span class="literal">nullptr</span>) {</span><br><span class="line"> *needs_native_bridge = <span class="literal">false</span>;</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">dlopen</span>(path, RTLD_NOW);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function">std::lock_guard<std::mutex> <span class="title">guard</span><span class="params">(g_namespaces_mutex)</span></span>;</span><br><span class="line"> NativeLoaderNamespace ns;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (!g_namespaces-><span class="built_in">FindNamespaceByClassLoader</span>(env, class_loader, &ns)) {</span><br><span class="line"> <span class="comment">// This is the case where the classloader was not created by ApplicationLoaders</span></span><br><span class="line"> <span class="comment">// In this case we create an isolated not-shared namespace for it.</span></span><br><span class="line"> <span class="keyword">if</span> (!g_namespaces-><span class="built_in">Create</span>(env,</span><br><span class="line"> target_sdk_version,</span><br><span class="line"> class_loader,</span><br><span class="line"> <span class="literal">false</span> <span class="comment">/* is_shared */</span>,</span><br><span class="line"> <span class="literal">false</span> <span class="comment">/* is_for_vendor */</span>,</span><br><span class="line"> library_path,</span><br><span class="line"> <span class="literal">nullptr</span>,</span><br><span class="line"> &ns,</span><br><span class="line"> error_msg)) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">nullptr</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ns.<span class="built_in">is_android_namespace</span>()) {</span><br><span class="line"> android_dlextinfo extinfo;</span><br><span class="line"> extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;</span><br><span class="line"> extinfo.library_namespace = ns.<span class="built_in">get_android_ns</span>();</span><br><span class="line"></span><br><span class="line"> <span class="type">void</span>* handle = <span class="built_in">android_dlopen_ext</span>(path, RTLD_NOW, &extinfo);</span><br><span class="line"> <span class="keyword">if</span> (handle == <span class="literal">nullptr</span>) {</span><br><span class="line"> *error_msg = <span class="built_in">dlerror</span>();</span><br><span class="line"> }</span><br><span class="line"> *needs_native_bridge = <span class="literal">false</span>;</span><br><span class="line"> <span class="keyword">return</span> handle;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="type">void</span>* handle = <span class="built_in">NativeBridgeLoadLibraryExt</span>(path, RTLD_NOW, ns.<span class="built_in">get_native_bridge_ns</span>());</span><br><span class="line"> <span class="keyword">if</span> (handle == <span class="literal">nullptr</span>) {</span><br><span class="line"> *error_msg = <span class="built_in">NativeBridgeGetError</span>();</span><br><span class="line"> }</span><br><span class="line"> *needs_native_bridge = <span class="literal">true</span>;</span><br><span class="line"> <span class="keyword">return</span> handle;</span><br><span class="line"> }</span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line"> <span class="built_in">UNUSED</span>(env, target_sdk_version, class_loader);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Do some best effort to emulate library-path support. It will not</span></span><br><span class="line"> <span class="comment">// work for dependencies.</span></span><br><span class="line"> <span class="comment">//</span></span><br><span class="line"> <span class="comment">// Note: null has a special meaning and must be preserved.</span></span><br><span class="line"> std::string c_library_path; <span class="comment">// Empty string by default.</span></span><br><span class="line"> <span class="keyword">if</span> (library_path != <span class="literal">nullptr</span> && path != <span class="literal">nullptr</span> && path[<span class="number">0</span>] != <span class="string">'/'</span>) {</span><br><span class="line"> <span class="function">ScopedUtfChars <span class="title">library_path_utf_chars</span><span class="params">(env, library_path)</span></span>;</span><br><span class="line"> c_library_path = library_path_utf_chars.<span class="built_in">c_str</span>();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> std::vector<std::string> library_paths = base::<span class="built_in">Split</span>(c_library_path, <span class="string">":"</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="type">const</span> std::string& lib_path : library_paths) {</span><br><span class="line"> *needs_native_bridge = <span class="literal">false</span>;</span><br><span class="line"> <span class="type">const</span> <span class="type">char</span>* path_arg;</span><br><span class="line"> std::string complete_path;</span><br><span class="line"> <span class="keyword">if</span> (path == <span class="literal">nullptr</span>) {</span><br><span class="line"> <span class="comment">// Preserve null.</span></span><br><span class="line"> path_arg = <span class="literal">nullptr</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> complete_path = lib_path;</span><br><span class="line"> <span class="keyword">if</span> (!complete_path.<span class="built_in">empty</span>()) {</span><br><span class="line"> complete_path.<span class="built_in">append</span>(<span class="string">"/"</span>);</span><br><span class="line"> }</span><br><span class="line"> complete_path.<span class="built_in">append</span>(path);</span><br><span class="line"> path_arg = complete_path.<span class="built_in">c_str</span>();</span><br><span class="line"> }</span><br><span class="line"> <span class="type">void</span>* handle = <span class="built_in">dlopen</span>(path_arg, RTLD_NOW);</span><br><span class="line"> <span class="keyword">if</span> (handle != <span class="literal">nullptr</span>) {</span><br><span class="line"> <span class="keyword">return</span> handle;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">NativeBridgeIsSupported</span>(path_arg)) {</span><br><span class="line"> *needs_native_bridge = <span class="literal">true</span>;</span><br><span class="line"> handle = <span class="built_in">NativeBridgeLoadLibrary</span>(path_arg, RTLD_NOW);</span><br><span class="line"> <span class="keyword">if</span> (handle != <span class="literal">nullptr</span>) {</span><br><span class="line"> <span class="keyword">return</span> handle;</span><br><span class="line"> }</span><br><span class="line"> *error_msg = <span class="built_in">NativeBridgeGetError</span>();</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> *error_msg = <span class="built_in">dlerror</span>();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">nullptr</span>;</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>这段主要是加载Native库的代码。可参考:</p>
<p><a href="https://cloud.tencent.com/developer/article/1034856">https://cloud.tencent.com/developer/article/1034856</a></p>
<p><a href="https://blog.csdn.net/edonlii/article/details/8445239">https://blog.csdn.net/edonlii/article/details/8445239</a></p>
<h4 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h4><p>Android在启动AndroidManifest.xml中配置的android.app.NativeActivity后,主要完成了一下工作:</p>
<ol>
<li>通过libname获取NativeCode,并将android.app.NativeActivity的生命周期方法交给NativeCode处理,并托管Surface、InputQueue给Native</li>
<li>在加载NativeCode对应的库时,通过OpenNativeLibrary加载Native库,进行一些列设置后,执行Native库中funcname对于的方法,用来创建原生的Native App。</li>
</ol>
<p>/<a href="http://androidxref.com/9.0.0_r3/xref/external/">external</a>/<a href="http://androidxref.com/9.0.0_r3/xref/external/skia/">skia</a>/<a href="http://androidxref.com/9.0.0_r3/xref/external/skia/tools/">tools</a>/<a href="http://androidxref.com/9.0.0_r3/xref/external/skia/tools/sk_app/">sk_app</a>/<a href="http://androidxref.com/9.0.0_r3/xref/external/skia/tools/sk_app/android/">android</a>/<a href="http://androidxref.com/9.0.0_r3/xref/external/skia/tools/sk_app/android/main_android.cpp">main_android.cpp</a></p>
<p>/<a href="http://androidxref.com/9.0.0_r3/xref/external/">external</a>/<a href="http://androidxref.com/9.0.0_r3/xref/external/flatbuffers/">flatbuffers</a>/<a href="http://androidxref.com/9.0.0_r3/xref/external/flatbuffers/android/">android</a>/<a href="http://androidxref.com/9.0.0_r3/xref/external/flatbuffers/android/jni/">jni</a>/<a href="http://androidxref.com/9.0.0_r3/xref/external/flatbuffers/android/jni/main.cpp">main.cpp</a></p>
<p>/<a href="http://androidxref.com/9.0.0_r3/xref/prebuilts/">prebuilts</a>/<a href="http://androidxref.com/9.0.0_r3/xref/prebuilts/ndk/">ndk</a>/<a href="http://androidxref.com/9.0.0_r3/xref/prebuilts/ndk/current/">current</a>/<a href="http://androidxref.com/9.0.0_r3/xref/prebuilts/ndk/current/sources/">sources</a>/<a href="http://androidxref.com/9.0.0_r3/xref/prebuilts/ndk/current/sources/android/">android</a>/<a href="http://androidxref.com/9.0.0_r3/xref/prebuilts/ndk/current/sources/android/native_app_glue/">native_app_glue</a>/<a href="http://androidxref.com/9.0.0_r3/xref/prebuilts/ndk/current/sources/android/native_app_glue/android_native_app_glue.c">android_native_app_glue.c</a></p>
<h3 id="0x04-附录:CMake简单实用"><a href="#0x04-附录:CMake简单实用" class="headerlink" title="0x04 附录:CMake简单实用"></a>0x04 附录:CMake简单实用</h3>]]></content>
<categories>
<category>Android</category>
</categories>
</entry>
<entry>
<title>Chromiun Android 编译</title>
<url>/2021/05/13/Chromiun%20Android%20%E7%BC%96%E8%AF%91/</url>
<content><![CDATA[<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git</span><br><span class="line">export PATH=$PATH:/home/zauther/Libraries/depot_tools</span><br><span class="line">fetch --nohooks android</span><br><span class="line"></span><br><span class="line">gclient sync</span><br><span class="line">build/install-build-deps-android.sh</span><br><span class="line">gclient runhooks</span><br></pre></td></tr></table></figure>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">gn args out/Default</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">></span><span class="language-bash">></span> </span><br><span class="line">target_os = "android"</span><br><span class="line">target_cpu = "arm64"</span><br><span class="line">treat_warnings_as_errors=false</span><br><span class="line"></span><br><span class="line">autoninja -C out/Default chrome_public_apk</span><br></pre></td></tr></table></figure>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">build/android/gradle/generate_gradle.py --output-directory out/Default --project-dir out/Chrome-Android</span><br></pre></td></tr></table></figure>
<figure class="highlight python"><table><tr><td class="code"><pre><span class="line">git checkout <span class="number">92.0</span><span class="number">.4480</span><span class="number">.2</span></span><br><span class="line">gclient sync --with_branch_heads</span><br></pre></td></tr></table></figure>
<span id="more"></span>
<h4 id="网络问题"><a href="#网络问题" class="headerlink" title="网络问题"></a>网络问题</h4><ol>
<li>CIPD selfupdate failed. Trying to bootstrap the CIPD client from scratch</li>
<li>OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to 127.0.0.1:1087</li>
</ol>
<p>解决办法:<br>git使用代理,并且是sock5代理,http会出现第二个问题</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">export socks_proxy=scoks5://127.0.0.1:1080</span><br><span class="line"></span><br><span class="line">export http_proxy=http://127.0.0.1:1087 </span><br><span class="line">export https_proxy=http://127.0.0.1:1087</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">git config --global http.proxy 'socks5://127.0.0.1:1080'</span><br><span class="line">git config --global https.proxy 'socks5://127.0.0.1:1080'</span><br></pre></td></tr></table></figure>
<p>NameError: name ‘unicode’ is not defined<br>–plugin_out: protoc-gen-plugin: Plugin failed with status code 1.</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">sudo ln -f /usr/bin/python2 /usr/bin/python</span><br></pre></td></tr></table></figure>
]]></content>
<categories>
<category>Android</category>
</categories>
<tags>
<tag>Android</tag>
<tag>Chromiun</tag>
</tags>
</entry>
<entry>
<title>Flutter Engine 编译</title>
<url>/2020/02/06/Flutter-Engine-%E7%BC%96%E8%AF%91/</url>
<content><![CDATA[<h3 id="一、编译Flutter-Engine"><a href="#一、编译Flutter-Engine" class="headerlink" title="一、编译Flutter Engine"></a>一、编译Flutter Engine</h3><ol>
<li><p>创建工作目录 engine</p>
</li>
<li><p>添加 <a href="http://commondatastorage.googleapis.com/chrome-infra-docs/flat/depot_tools/docs/html/depot_tools_tutorial.html#_setting_up">depot_tools</a> 到环境变量,并在engine目录下创建.gclient文件</p>
<figure class="highlight txt"><table><tr><td class="code"><pre><span class="line">solutions = [</span><br><span class="line"> {</span><br><span class="line"> "managed": False,</span><br><span class="line"> "name": "src/flutter",</span><br><span class="line"> "url": "git@github.com:<your_name_here>/engine.git",</span><br><span class="line"> "custom_deps": {},</span><br><span class="line"> "deps_file": "DEPS",</span><br><span class="line"> "safesync_url": "",</span><br><span class="line"> },</span><br><span class="line">]</span><br></pre></td></tr></table></figure>
</li>
<li><p>在engine目录执行 <code>gclient sync</code> 命令同步源码和编译工具链</p>
</li>
<li><p>进入 <code>engine/src</code> 目录下,如果是linux平台执行:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">sudo ./build/install-build-deps-android.sh</span><br><span class="line">sudo ./build/install-build-deps.sh</span><br><span class="line"></span><br><span class="line">sudo ./flutter/build/install-build-deps-linux-desktop.sh</span><br></pre></td></tr></table></figure>
<p>如果是mac平台,安装jdk 1.8 和ant:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">brew install ant</span><br></pre></td></tr></table></figure>
</li>
<li><p>在<code>engine/src</code> 目录下,生成编译配置文件</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">./flutter/tools/gn --android --unoptimized</span><br></pre></td></tr></table></figure>
<p>生成目录 <code>engine/src/out/android_debug_unopt</code></p>
</li>
<li><p>在<code>engine/src</code> 目录下,执行编译命令</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">ninja -C out/android_debug_unopt</span><br></pre></td></tr></table></figure></li>
</ol>
<h3 id="二、如何在mac下编译linux平台的产物?"><a href="#二、如何在mac下编译linux平台的产物?" class="headerlink" title="二、如何在mac下编译linux平台的产物?"></a>二、如何在mac下编译linux平台的产物?</h3><span id="more"></span>
<ol>
<li><p>创建docker镜像,由于需要科学上网,需要自行设置代理</p>
<figure class="highlight dockerfile"><table><tr><td class="code"><pre><span class="line"><span class="keyword">FROM</span> ubuntu:<span class="number">16.04</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">ENV</span> DEPOT_TOOLS_PATH /home/admin/depot_tools</span><br><span class="line"><span class="keyword">ENV</span> BUILDROOT_PATH /home/admin/buildroot</span><br><span class="line"><span class="keyword">ENV</span> PATH $PATH:$DEPOT_TOOLS_PATH</span><br><span class="line"></span><br><span class="line"><span class="comment"># Notes:</span></span><br><span class="line"><span class="comment"># - libx11-dev is used by Flutter for desktop linux (see also install-build-deps-linux-desktop.sh)</span></span><br><span class="line"> <span class="comment"># - chrome is used by Flutter for web.</span></span><br><span class="line"> <span class="keyword">RUN</span><span class="language-bash"> <span class="built_in">export</span> http_proxy=http://*.*.*.*:*** && \</span></span><br><span class="line"><span class="language-bash"> <span class="built_in">export</span> https_proxy=http://*.*.*.*:*** && \</span></span><br><span class="line"><span class="language-bash"> <span class="built_in">export</span> socks_proxy=socks://*.*.*.*:*** && \</span></span><br><span class="line"><span class="language-bash"> apt-get update && \</span></span><br><span class="line"><span class="language-bash"> apt-get install -y sudo wget zip unzip git lsb-release openssh-client curl apt-transport-https libx11-dev software-properties-common build-essential libfreetype6-dev lib32stdc++6 libstdc++6 libpulse0 libglu1-mesa python pkg-config && \</span></span><br><span class="line"><span class="language-bash"> git <span class="built_in">clone</span> https://chromium.googlesource.com/chromium/tools/depot_tools.git <span class="variable">$DEPOT_TOOLS_PATH</span> && \</span></span><br><span class="line"><span class="language-bash"> git config --global http.proxy http://*.*.*.*:*** && \</span></span><br><span class="line"><span class="language-bash"> git config --global https.proxy http://*.*.*.*:*** && \ </span></span><br><span class="line"> git clone https://github.com/flutter/buildroot.git $BUILDROOT_PATH && \</span><br><span class="line"> cd $BUILDROOT_PATH && \</span><br><span class="line"> ./build/install-build-deps.sh --no-prompt && \</span><br><span class="line"> ./build/install-build-deps-android.sh --no-prompt && \</span><br><span class="line"> apt-get clean</span><br><span class="line"> <span class="keyword">RUN</span><span class="language-bash"> git config --global --<span class="built_in">unset</span> http.proxy && \</span></span><br><span class="line"><span class="language-bash"> git config --global --<span class="built_in">unset</span> https.proxy && \</span></span><br><span class="line"><span class="language-bash"> <span class="built_in">unset</span> http_proxy && \</span></span><br><span class="line"><span class="language-bash"> <span class="built_in">unset</span> https_proxy && \</span></span><br><span class="line"><span class="language-bash"> <span class="built_in">unset</span> socks_proxy && \</span></span><br><span class="line"><span class="language-bash"> <span class="built_in">chmod</span> -R 777 <span class="variable">$DEPOT_TOOLS_PATH</span> &&</span></span><br></pre></td></tr></table></figure>
<p>创建image</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">docker build --rm -f "Dockerfile" -t flutter-engine-bulder:latest "."</span><br></pre></td></tr></table></figure>
</li>
<li><p>拉去镜像,如果是本地构建的镜像,则已经存在,如果上传到hub上,则拉去</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">docker images | grep flutter-engine-bulder &>/dev/null</span><br><span class="line">if [ $? -ne 0 ]; then</span><br><span class="line"> echo "flutter-engine-bulder does not exist,we will docker pull it"</span><br><span class="line"> docker pull flutter-engine-bulder:latest</span><br><span class="line">else</span><br><span class="line"> echo "flutter-engine-bulder already exists"</span><br><span class="line">fi</span><br></pre></td></tr></table></figure>
</li>
<li><p>通过docker 执行gclient sync,将宿主的源码目录engine映射到容器内/home/admin/engine,</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">docker run --rm --privileged=true -v engine:/home/admin/engine -w /home/admin/engine/ flutter-engine-bulder:latest gclient sync</span><br></pre></td></tr></table></figure>
</li>
<li><p>生成配置文件</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">docker run --rm --privileged=true -v engine:/home/admin/engine -w /home/admin/engine/src flutter-engine-bulder:latest ./flutter/tools/gn --android --unoptimized</span><br></pre></td></tr></table></figure>
</li>
<li><p>执行编译</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">docker run --rm --privileged=true -v engine:/home/admin/engine -w /home/admin/engine/src flutter-engine-bulder:latest ninja -C out/android_debug_unopt</span><br></pre></td></tr></table></figure></li>
</ol>
<p>docker编译如果很慢,可以自行根据电脑性能设置docker参数:</p>
<ol>
<li>增大docker可使用的cpu核心数</li>
<li>增加docker可使用的内存</li>
<li>增加docker可使用的交换空间,如果交换空间太小,会出现clang错误</li>
</ol>
<p>在运行容器时,使用4核cpu编译:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">docker run --rm --privileged=true --cpus=4 -v engine:/home/admin/engine -w /home/admin/engine/src flutter-engine-bulder:latest ninja -C out/android_debug_unopt</span><br></pre></td></tr></table></figure>
<hr>
<h3 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h3><p><a href="https://github.com/flutter/flutter/wiki/Setting-up-the-Engine-development-environment">https://github.com/flutter/flutter/wiki/Setting-up-the-Engine-development-environment</a></p>
<p><a href="https://github.com/flutter/flutter/wiki/Compiling-the-engine">https://github.com/flutter/flutter/wiki/Compiling-the-engine</a></p>
<p><a href="https://github.com/flutter/engine/blob/master/ci/docker/build/Dockerfile">https://github.com/flutter/engine/blob/master/ci/docker/build/Dockerfile</a></p>
<p><a href="https://github.com/flutter/engine/blob/master/.cirrus.yml">https://github.com/flutter/engine/blob/master/.cirrus.yml</a></p>
]]></content>
<categories>
<category>Flutter</category>
</categories>
<tags>
<tag>Flutter</tag>
</tags>
</entry>
<entry>
<title>Flutter Android 初始化流程</title>
<url>/2022/05/10/Flutter-Android-%E5%88%9D%E5%A7%8B%E5%8C%96%E6%B5%81%E7%A8%8B/</url>
<content><![CDATA[<h4 id="Flutter-UI容器"><a href="#Flutter-UI容器" class="headerlink" title="Flutter UI容器"></a>Flutter UI容器</h4><h5 id="承载Flutter的Android容器"><a href="#承载Flutter的Android容器" class="headerlink" title="承载Flutter的Android容器"></a>承载Flutter的Android容器</h5><p>Flutter容器包含有FlutterActivity和FlutterFragmentActivity。他们分别实现了<code>Provider</code>, <code>PluginRegistry</code>, <code>ViewFactory</code>,二者的方法主要通过<code>FlutterActivityDelegate</code> 代理出去</p>
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentStyleType="text/css" height="278px" preserveAspectRatio="none" style="width:888px;height:278px;background:#FFFFFF;" version="1.1" viewBox="0 0 888 278" width="888px" zoomAndPan="magnify"><defs/><g><!--MD5=[e72aae6de22b09cdc9529a59d7fca5eb]
class FlutterActivityDelegate--><g id="elem_FlutterActivityDelegate"><rect codeLine="1" fill="#F1F1F1" height="48" id="FlutterActivityDelegate" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="186" x="252" y="223"/><ellipse cx="267" cy="239" fill="#ADD1B2" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M269.9688,244.6406 Q269.3906,244.9375 268.75,245.0781 Q268.1094,245.2344 267.4063,245.2344 Q264.9063,245.2344 263.5781,243.5938 Q262.2656,241.9375 262.2656,238.8125 Q262.2656,235.6875 263.5781,234.0313 Q264.9063,232.375 267.4063,232.375 Q268.1094,232.375 268.75,232.5313 Q269.4063,232.6875 269.9688,232.9844 L269.9688,235.7031 Q269.3438,235.125 268.75,234.8594 Q268.1563,234.5781 267.5313,234.5781 Q266.1875,234.5781 265.5,235.6563 Q264.8125,236.7188 264.8125,238.8125 Q264.8125,240.9063 265.5,241.9844 Q266.1875,243.0469 267.5313,243.0469 Q268.1563,243.0469 268.75,242.7813 Q269.3438,242.5 269.9688,241.9219 L269.9688,244.6406 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="154" x="281" y="243.8467">FlutterActivityDelegate</text><line style="stroke:#181818;stroke-width:0.5;" x1="253" x2="437" y1="255" y2="255"/><line style="stroke:#181818;stroke-width:0.5;" x1="253" x2="437" y1="263" y2="263"/></g><!--MD5=[17641098b0a070581bab2e5cbfdafafe]
class FlutterActivityEvents--><g id="elem_FlutterActivityEvents"><rect fill="#F1F1F1" height="48" id="FlutterActivityEvents" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="170" x="7" y="115"/><ellipse cx="22" cy="131" fill="#B4A7E5" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M17.9219,126.7656 L17.9219,124.6094 L25.3125,124.6094 L25.3125,126.7656 L22.8438,126.7656 L22.8438,134.8438 L25.3125,134.8438 L25.3125,137 L17.9219,137 L17.9219,134.8438 L20.3906,134.8438 L20.3906,126.7656 L17.9219,126.7656 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="138" x="36" y="135.8467">FlutterActivityEvents</text><line style="stroke:#181818;stroke-width:0.5;" x1="8" x2="176" y1="147" y2="147"/><line style="stroke:#181818;stroke-width:0.5;" x1="8" x2="176" y1="155" y2="155"/></g><!--MD5=[3521822871a02163bc1090dd8c65b7f5]
class Provider--><g id="elem_Provider"><rect fill="#F1F1F1" height="48" id="Provider" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="88" x="184" y="7"/><ellipse cx="199" cy="23" fill="#B4A7E5" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M194.9219,18.7656 L194.9219,16.6094 L202.3125,16.6094 L202.3125,18.7656 L199.8438,18.7656 L199.8438,26.8438 L202.3125,26.8438 L202.3125,29 L194.9219,29 L194.9219,26.8438 L197.3906,26.8438 L197.3906,18.7656 L194.9219,18.7656 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="56" x="213" y="27.8467">Provider</text><line style="stroke:#181818;stroke-width:0.5;" x1="185" x2="271" y1="39" y2="39"/><line style="stroke:#181818;stroke-width:0.5;" x1="185" x2="271" y1="47" y2="47"/></g><!--MD5=[0bee35ff36c2bfe1d068cc18effabcca]
class PluginRegistry--><g id="elem_PluginRegistry"><rect fill="#F1F1F1" height="48" id="PluginRegistry" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="130" x="571" y="7"/><ellipse cx="586" cy="23" fill="#B4A7E5" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M581.9219,18.7656 L581.9219,16.6094 L589.3125,16.6094 L589.3125,18.7656 L586.8438,18.7656 L586.8438,26.8438 L589.3125,26.8438 L589.3125,29 L581.9219,29 L581.9219,26.8438 L584.3906,26.8438 L584.3906,18.7656 L581.9219,18.7656 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="98" x="600" y="27.8467">PluginRegistry</text><line style="stroke:#181818;stroke-width:0.5;" x1="572" x2="700" y1="39" y2="39"/><line style="stroke:#181818;stroke-width:0.5;" x1="572" x2="700" y1="47" y2="47"/></g><!--MD5=[f0a36ff588851750be7714682b8e0a08]
class FlutterActivity--><g id="elem_FlutterActivity"><rect codeLine="3" fill="#F1F1F1" height="48" id="FlutterActivity" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="123" x="283.5" y="115"/><ellipse cx="298.5" cy="131" fill="#ADD1B2" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M301.4688,136.6406 Q300.8906,136.9375 300.25,137.0781 Q299.6094,137.2344 298.9063,137.2344 Q296.4063,137.2344 295.0781,135.5938 Q293.7656,133.9375 293.7656,130.8125 Q293.7656,127.6875 295.0781,126.0313 Q296.4063,124.375 298.9063,124.375 Q299.6094,124.375 300.25,124.5313 Q300.9063,124.6875 301.4688,124.9844 L301.4688,127.7031 Q300.8438,127.125 300.25,126.8594 Q299.6563,126.5781 299.0313,126.5781 Q297.6875,126.5781 297,127.6563 Q296.3125,128.7188 296.3125,130.8125 Q296.3125,132.9063 297,133.9844 Q297.6875,135.0469 299.0313,135.0469 Q299.6563,135.0469 300.25,134.7813 Q300.8438,134.5 301.4688,133.9219 L301.4688,136.6406 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="91" x="312.5" y="135.8467">FlutterActivity</text><line style="stroke:#181818;stroke-width:0.5;" x1="284.5" x2="405.5" y1="147" y2="147"/><line style="stroke:#181818;stroke-width:0.5;" x1="284.5" x2="405.5" y1="155" y2="155"/></g><!--MD5=[c881b25adf3665c6568c9693d41a70f3]
class Activity--><g id="elem_Activity"><rect fill="#F1F1F1" height="48" id="Activity" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="79" x="307.5" y="7"/><ellipse cx="322.5" cy="23" fill="#ADD1B2" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M325.4688,28.6406 Q324.8906,28.9375 324.25,29.0781 Q323.6094,29.2344 322.9063,29.2344 Q320.4063,29.2344 319.0781,27.5938 Q317.7656,25.9375 317.7656,22.8125 Q317.7656,19.6875 319.0781,18.0313 Q320.4063,16.375 322.9063,16.375 Q323.6094,16.375 324.25,16.5313 Q324.9063,16.6875 325.4688,16.9844 L325.4688,19.7031 Q324.8438,19.125 324.25,18.8594 Q323.6563,18.5781 323.0313,18.5781 Q321.6875,18.5781 321,19.6563 Q320.3125,20.7188 320.3125,22.8125 Q320.3125,24.9063 321,25.9844 Q321.6875,27.0469 323.0313,27.0469 Q323.6563,27.0469 324.25,26.7813 Q324.8438,26.5 325.4688,25.9219 L325.4688,28.6406 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="47" x="336.5" y="27.8467">Activity</text><line style="stroke:#181818;stroke-width:0.5;" x1="308.5" x2="385.5" y1="39" y2="39"/><line style="stroke:#181818;stroke-width:0.5;" x1="308.5" x2="385.5" y1="47" y2="47"/></g><!--MD5=[6dd3dec888cfc650825cf24d563a6604]
class ViewFactory--><g id="elem_ViewFactory"><rect fill="#F1F1F1" height="48" id="ViewFactory" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="114" x="422" y="7"/><ellipse cx="437" cy="23" fill="#B4A7E5" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M432.9219,18.7656 L432.9219,16.6094 L440.3125,16.6094 L440.3125,18.7656 L437.8438,18.7656 L437.8438,26.8438 L440.3125,26.8438 L440.3125,29 L432.9219,29 L432.9219,26.8438 L435.3906,26.8438 L435.3906,18.7656 L432.9219,18.7656 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="82" x="451" y="27.8467">ViewFactory</text><line style="stroke:#181818;stroke-width:0.5;" x1="423" x2="535" y1="39" y2="39"/><line style="stroke:#181818;stroke-width:0.5;" x1="423" x2="535" y1="47" y2="47"/></g><!--MD5=[95ba53836d8309edeaf5cdc27f597766]
class FlutterFragmentActivity--><g id="elem_FlutterFragmentActivity"><rect codeLine="5" fill="#F1F1F1" height="48" id="FlutterFragmentActivity" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="189" x="441.5" y="115"/><ellipse cx="456.5" cy="131" fill="#ADD1B2" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M459.4688,136.6406 Q458.8906,136.9375 458.25,137.0781 Q457.6094,137.2344 456.9063,137.2344 Q454.4063,137.2344 453.0781,135.5938 Q451.7656,133.9375 451.7656,130.8125 Q451.7656,127.6875 453.0781,126.0313 Q454.4063,124.375 456.9063,124.375 Q457.6094,124.375 458.25,124.5313 Q458.9063,124.6875 459.4688,124.9844 L459.4688,127.7031 Q458.8438,127.125 458.25,126.8594 Q457.6563,126.5781 457.0313,126.5781 Q455.6875,126.5781 455,127.6563 Q454.3125,128.7188 454.3125,130.8125 Q454.3125,132.9063 455,133.9844 Q455.6875,135.0469 457.0313,135.0469 Q457.6563,135.0469 458.25,134.7813 Q458.8438,134.5 459.4688,133.9219 L459.4688,136.6406 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="157" x="470.5" y="135.8467">FlutterFragmentActivity</text><line style="stroke:#181818;stroke-width:0.5;" x1="442.5" x2="629.5" y1="147" y2="147"/><line style="stroke:#181818;stroke-width:0.5;" x1="442.5" x2="629.5" y1="155" y2="155"/></g><!--MD5=[c1be6ddf4ea56b75972dac491aee9766]
class FragmentActivity--><g id="elem_FragmentActivity"><rect fill="#F1F1F1" height="48" id="FragmentActivity" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="145" x="736.5" y="7"/><ellipse cx="751.5" cy="23" fill="#ADD1B2" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M754.4688,28.6406 Q753.8906,28.9375 753.25,29.0781 Q752.6094,29.2344 751.9063,29.2344 Q749.4063,29.2344 748.0781,27.5938 Q746.7656,25.9375 746.7656,22.8125 Q746.7656,19.6875 748.0781,18.0313 Q749.4063,16.375 751.9063,16.375 Q752.6094,16.375 753.25,16.5313 Q753.9063,16.6875 754.4688,16.9844 L754.4688,19.7031 Q753.8438,19.125 753.25,18.8594 Q752.6563,18.5781 752.0313,18.5781 Q750.6875,18.5781 750,19.6563 Q749.3125,20.7188 749.3125,22.8125 Q749.3125,24.9063 750,25.9844 Q750.6875,27.0469 752.0313,27.0469 Q752.6563,27.0469 753.25,26.7813 Q753.8438,26.5 754.4688,25.9219 L754.4688,28.6406 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="113" x="765.5" y="27.8467">FragmentActivity</text><line style="stroke:#181818;stroke-width:0.5;" x1="737.5" x2="880.5" y1="39" y2="39"/><line style="stroke:#181818;stroke-width:0.5;" x1="737.5" x2="880.5" y1="47" y2="47"/></g><!--MD5=[6d4d55b415ec57c63ba4ca1e9a2d1454]
reverse link FlutterActivityEvents to FlutterActivityDelegate--><g id="link_FlutterActivityEvents_FlutterActivityDelegate"><path d="M165.6,170.83 C205.25,187.45 253.36,207.6 289.77,222.86 " fill="none" id="FlutterActivityEvents-backto-FlutterActivityDelegate" style="stroke:#181818;stroke-width:1.0;stroke-dasharray:7.0,7.0;"/><polygon fill="none" points="162.64,177.19,146.9,163,168.05,164.27,162.64,177.19" style="stroke:#181818;stroke-width:1.0;"/></g><!--MD5=[d8bdc4c8f5a96ab1d8388734b1795cfd]
reverse link Provider to FlutterActivityDelegate--><g id="link_Provider_FlutterActivityDelegate"><path d="M235.06,74.94 C240.71,101.56 250.35,135.76 266,163 C279.18,185.94 299.99,207.45 316.94,222.82 " fill="none" id="Provider-backto-FlutterActivityDelegate" style="stroke:#181818;stroke-width:1.0;stroke-dasharray:7.0,7.0;"/><polygon fill="none" points="228.14,76.04,231.28,55.08,241.9,73.42,228.14,76.04" style="stroke:#181818;stroke-width:1.0;"/></g><!--MD5=[2a74c99e06d90302b256aa11a4b2bb19]
reverse link PluginRegistry to FlutterActivityDelegate--><g id="link_PluginRegistry_FlutterActivityDelegate"><path d="M653.61,74.27 C662.18,102.18 667.02,138.06 648,163 C622.44,196.5 517.37,219.79 438.07,233 " fill="none" id="PluginRegistry-backto-FlutterActivityDelegate" style="stroke:#181818;stroke-width:1.0;stroke-dasharray:7.0,7.0;"/><polygon fill="none" points="646.94,76.41,646.82,55.22,660.13,71.71,646.94,76.41" style="stroke:#181818;stroke-width:1.0;"/></g><!--MD5=[5e61f2a041a633b8c2079a852f7c44fe]
reverse link Activity to FlutterActivity--><g id="link_Activity_FlutterActivity"><path d="M346.19,75.02 C345.93,88.58 345.66,103.04 345.44,114.68 " fill="none" id="Activity-backto-FlutterActivity" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="none" points="339.19,74.86,346.57,55,353.19,75.13,339.19,74.86" style="stroke:#181818;stroke-width:1.0;"/></g><!--MD5=[7757f424729984e3242432d4ebefb3a0]
reverse link Provider to FlutterActivity--><g id="link_Provider_FlutterActivity"><path d="M268.37,68.57 C285.24,83.86 304.35,101.17 319.26,114.68 " fill="none" id="Provider-backto-FlutterActivity" style="stroke:#181818;stroke-width:1.0;stroke-dasharray:7.0,7.0;"/><polygon fill="none" points="263.51,73.62,253.39,55,272.91,63.24,263.51,73.62" style="stroke:#181818;stroke-width:1.0;"/></g><!--MD5=[54c94e77e73502f23afb08d6de1be88a]
reverse link PluginRegistry to FlutterActivity--><g id="link_PluginRegistry_FlutterActivity"><path d="M553.87,61.92 C507.07,78.96 449.4,99.97 406.52,115.59 " fill="none" id="PluginRegistry-backto-FlutterActivity" style="stroke:#181818;stroke-width:1.0;stroke-dasharray:7.0,7.0;"/><polygon fill="none" points="551.67,55.27,572.86,55,556.46,68.42,551.67,55.27" style="stroke:#181818;stroke-width:1.0;"/></g><!--MD5=[02840d13fe8e09ddd7a33fca926f00af]
reverse link ViewFactory to FlutterActivity--><g id="link_ViewFactory_FlutterActivity"><path d="M433.95,67.64 C414.34,83.15 391.91,100.89 374.48,114.68 " fill="none" id="ViewFactory-backto-FlutterActivity" style="stroke:#181818;stroke-width:1.0;stroke-dasharray:7.0,7.0;"/><polygon fill="none" points="429.9,61.92,449.92,55,438.58,72.9,429.9,61.92" style="stroke:#181818;stroke-width:1.0;"/></g><!--MD5=[96f9ec98428bc9abb5cd714519aacf0a]
reverse link FragmentActivity to FlutterFragmentActivity--><g id="link_FragmentActivity_FlutterFragmentActivity"><path d="M731.04,62.27 C687.98,78.99 635.33,99.43 595.59,114.86 " fill="none" id="FragmentActivity-backto-FlutterFragmentActivity" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="none" points="728.59,55.71,749.76,55,733.65,68.76,728.59,55.71" style="stroke:#181818;stroke-width:1.0;"/></g><!--MD5=[5454928cf2c2f9c0033a141dc9ff403b]
reverse link Provider to FlutterFragmentActivity--><g id="link_Provider_FlutterFragmentActivity"><path d="M291.44,55.4 C360.26,79.68 420.65,99.96 465.82,114.94 " fill="none" id="Provider-backto-FlutterFragmentActivity" style="stroke:#181818;stroke-width:1.0;stroke-dasharray:7.0,7.0;"/><polygon fill="none" points="288.82,61.9,272.31,48.62,293.5,48.7,288.82,61.9" style="stroke:#181818;stroke-width:1.0;"/></g><!--MD5=[4e4ed14277b66b157851f2d6c9c8e1e2]
reverse link PluginRegistry to FlutterFragmentActivity--><g id="link_PluginRegistry_FlutterFragmentActivity"><path d="M600.38,69.75 C586.24,84.74 570.42,101.51 558,114.68 " fill="none" id="PluginRegistry-backto-FlutterFragmentActivity" style="stroke:#181818;stroke-width:1.0;stroke-dasharray:7.0,7.0;"/><polygon fill="none" points="595.49,64.74,614.3,55,605.67,74.35,595.49,64.74" style="stroke:#181818;stroke-width:1.0;"/></g><!--MD5=[3c53dad8fd8b1afd02392a60716f39ed]
reverse link ViewFactory to FlutterFragmentActivity--><g id="link_ViewFactory_FlutterFragmentActivity"><path d="M501.1,73.09 C508.68,87.2 516.9,102.48 523.46,114.68 " fill="none" id="ViewFactory-backto-FlutterFragmentActivity" style="stroke:#181818;stroke-width:1.0;stroke-dasharray:7.0,7.0;"/><polygon fill="none" points="494.68,75.93,491.37,55,507.01,69.3,494.68,75.93" style="stroke:#181818;stroke-width:1.0;"/></g><!--MD5=[bdfed072028aaf26f53ff1a8514797ca]
link FlutterActivity to FlutterActivityDelegate--><g id="link_FlutterActivity_FlutterActivityDelegate"><path codeLine="7" d="M345,163 C345,179 345,200.45 345,217.53 " fill="none" id="FlutterActivity-to-FlutterActivityDelegate" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="345,222.68,349,213.68,345,217.68,341,213.68,345,222.68" style="stroke:#181818;stroke-width:1.0;"/></g><!--MD5=[ecf2073e99c3d2dba415b1cf3afe2fab]
link FlutterFragmentActivity to FlutterActivityDelegate--><g id="link_FlutterFragmentActivity_FlutterActivityDelegate"><path codeLine="8" d="M494.56,163 C464.13,179.89 422.78,202.84 391.27,220.32 " fill="none" id="FlutterFragmentActivity-to-FlutterActivityDelegate" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="386.69,222.86,396.5021,222.0104,391.0668,220.4427,392.6345,215.0074,386.69,222.86" style="stroke:#181818;stroke-width:1.0;"/></g><!--MD5=[a7506a3f2f147ae3a7b7f9b0b5b8113a]
@startuml
class FlutterActivityDelegate implements FlutterActivityEvents, Provider, PluginRegistry
class FlutterActivity extends Activity implements Provider, PluginRegistry, ViewFactory
class FlutterFragmentActivity extends FragmentActivity implements Provider, PluginRegistry, ViewFactory
FlutterActivity - -> FlutterActivityDelegate
FlutterFragmentActivity - -> FlutterActivityDelegate
@enduml
PlantUML version 1.2022.4(Sat Apr 09 13:29:17 UTC 2022)
(GPL source distribution)
Java Runtime: OpenJDK Runtime Environment
JVM: OpenJDK 64-Bit Server VM
Default Encoding: UTF-8
Language: en
Country: null
--></g></svg>
<span id="more"></span>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">FlutterActivity</span> <span class="keyword">extends</span> <span class="title class_">Activity</span> <span class="keyword">implements</span> <span class="title class_">Provider</span>, PluginRegistry, ViewFactory{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> <span class="type">FlutterActivityDelegate</span> <span class="variable">delegate</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FlutterActivityDelegate</span>(<span class="built_in">this</span>, <span class="built_in">this</span>);</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> FlutterActivityEvents eventDelegate;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> Provider viewProvider;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> PluginRegistry pluginRegistry;</span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">FlutterActivity</span><span class="params">()</span> {</span><br><span class="line"> <span class="built_in">this</span>.eventDelegate = <span class="built_in">this</span>.delegate;</span><br><span class="line"> <span class="built_in">this</span>.viewProvider = <span class="built_in">this</span>.delegate;</span><br><span class="line"> <span class="built_in">this</span>.pluginRegistry = <span class="built_in">this</span>.delegate;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">FlutterFragmentActivity</span> <span class="keyword">extends</span> <span class="title class_">FragmentActivity</span> <span class="keyword">implements</span> <span class="title class_">Provider</span>, PluginRegistry, ViewFactory {</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> <span class="type">FlutterActivityDelegate</span> <span class="variable">delegate</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FlutterActivityDelegate</span>(<span class="built_in">this</span>, <span class="built_in">this</span>);</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> FlutterActivityEvents eventDelegate;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> Provider viewProvider;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> PluginRegistry pluginRegistry;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">FlutterFragmentActivity</span><span class="params">()</span> {</span><br><span class="line"> <span class="built_in">this</span>.eventDelegate = <span class="built_in">this</span>.delegate;</span><br><span class="line"> <span class="built_in">this</span>.viewProvider = <span class="built_in">this</span>.delegate;</span><br><span class="line"> <span class="built_in">this</span>.pluginRegistry = <span class="built_in">this</span>.delegate;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>其中 <code>Provider</code> 负责提供FlutterView</p>
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentStyleType="text/css" height="85px" preserveAspectRatio="none" style="width:222px;height:85px;background:#FFFFFF;" version="1.1" viewBox="0 0 222 85" width="222px" zoomAndPan="magnify"><defs/><g><!--MD5=[3521822871a02163bc1090dd8c65b7f5]
class Provider--><g id="elem_Provider"><rect codeLine="1" fill="#F1F1F1" height="64.2969" id="Provider" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="201" x="7" y="7"/><ellipse cx="75.25" cy="23" fill="#B4A7E5" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M71.1719,18.7656 L71.1719,16.6094 L78.5625,16.6094 L78.5625,18.7656 L76.0938,18.7656 L76.0938,26.8438 L78.5625,26.8438 L78.5625,29 L71.1719,29 L71.1719,26.8438 L73.6406,26.8438 L73.6406,18.7656 L71.1719,18.7656 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="56" x="95.75" y="27.8467">Provider</text><line style="stroke:#181818;stroke-width:0.5;" x1="8" x2="207" y1="39" y2="39"/><line style="stroke:#181818;stroke-width:0.5;" x1="8" x2="207" y1="47" y2="47"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="189" x="13" y="63.9951">FlutterView getFlutterView()</text></g><!--MD5=[016cced17aa1656ac4b1220b7f63625f]
@startuml
interface Provider{
FlutterView getFlutterView()
}
@enduml
PlantUML version 1.2022.4(Sat Apr 09 13:29:17 UTC 2022)
(GPL source distribution)
Java Runtime: OpenJDK Runtime Environment
JVM: OpenJDK 64-Bit Server VM
Default Encoding: UTF-8
Language: en
Country: null
--></g></svg>
<p><code>PluginRegistry</code>负责插件管理</p>
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentStyleType="text/css" height="117px" preserveAspectRatio="none" style="width:368px;height:117px;background:#FFFFFF;" version="1.1" viewBox="0 0 368 117" width="368px" zoomAndPan="magnify"><defs/><g><!--MD5=[0bee35ff36c2bfe1d068cc18effabcca]
class PluginRegistry--><g id="elem_PluginRegistry"><rect codeLine="1" fill="#F1F1F1" height="96.8906" id="PluginRegistry" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="347" x="7" y="7"/><ellipse cx="127.25" cy="23" fill="#B4A7E5" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M123.1719,18.7656 L123.1719,16.6094 L130.5625,16.6094 L130.5625,18.7656 L128.0938,18.7656 L128.0938,26.8438 L130.5625,26.8438 L130.5625,29 L123.1719,29 L123.1719,26.8438 L125.6406,26.8438 L125.6406,18.7656 L123.1719,18.7656 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="98" x="147.75" y="27.8467">PluginRegistry</text><line style="stroke:#181818;stroke-width:0.5;" x1="8" x2="353" y1="39" y2="39"/><line style="stroke:#181818;stroke-width:0.5;" x1="8" x2="353" y1="47" y2="47"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="335" x="13" y="63.9951">PluginRegistry.Registrar registrarFor(String var1);</text><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="215" x="13" y="80.292">boolean hasPlugin(String var1);</text><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="301" x="13" y="96.5889"><T> T valuePublishedByPlugin(String var1);</text></g><!--MD5=[0f2025c2beecc190146d3894637fbcd5]
@startuml
interface PluginRegistry {
PluginRegistry.Registrar registrarFor(String var1);
boolean hasPlugin(String var1);
<T> T valuePublishedByPlugin(String var1);
}
@enduml
PlantUML version 1.2022.4(Sat Apr 09 13:29:17 UTC 2022)
(GPL source distribution)
Java Runtime: OpenJDK Runtime Environment
JVM: OpenJDK 64-Bit Server VM
Default Encoding: UTF-8
Language: en
Country: null
--></g></svg>
<p><code>ViewFactory</code> 负责管理FlutterView和FlutterNative</p>
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentStyleType="text/css" height="117px" preserveAspectRatio="none" style="width:335px;height:117px;background:#FFFFFF;" version="1.1" viewBox="0 0 335 117" width="335px" zoomAndPan="magnify"><defs/><g><!--MD5=[6dd3dec888cfc650825cf24d563a6604]
class ViewFactory--><g id="elem_ViewFactory"><rect codeLine="1" fill="#F1F1F1" height="96.8906" id="ViewFactory" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="314" x="7" y="7"/><ellipse cx="118.75" cy="23" fill="#B4A7E5" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M114.6719,18.7656 L114.6719,16.6094 L122.0625,16.6094 L122.0625,18.7656 L119.5938,18.7656 L119.5938,26.8438 L122.0625,26.8438 L122.0625,29 L114.6719,29 L114.6719,26.8438 L117.1406,26.8438 L117.1406,18.7656 L114.6719,18.7656 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="82" x="139.25" y="27.8467">ViewFactory</text><line style="stroke:#181818;stroke-width:0.5;" x1="8" x2="320" y1="39" y2="39"/><line style="stroke:#181818;stroke-width:0.5;" x1="8" x2="320" y1="47" y2="47"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="302" x="13" y="63.9951">FlutterView createFlutterView(Context var1);</text><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="299" x="13" y="80.292">FlutterNativeView createFlutterNativeView();</text><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="232" x="13" y="96.5889">boolean retainFlutterNativeView();</text></g><!--MD5=[a5ccf00d8a809148ec13a598c48706b3]
@startuml
interface ViewFactory {
FlutterView createFlutterView(Context var1);
FlutterNativeView createFlutterNativeView();
boolean retainFlutterNativeView();
}
@enduml
PlantUML version 1.2022.4(Sat Apr 09 13:29:17 UTC 2022)
(GPL source distribution)
Java Runtime: OpenJDK Runtime Environment
JVM: OpenJDK 64-Bit Server VM
Default Encoding: UTF-8
Language: en
Country: null
--></g></svg>
<h5 id="Flutter容器代理类-FlutterActivityDelegate"><a href="#Flutter容器代理类-FlutterActivityDelegate" class="headerlink" title="Flutter容器代理类 FlutterActivityDelegate"></a>Flutter容器代理类 FlutterActivityDelegate</h5><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">class</span> <span class="title class_">FlutterActivityDelegate</span> <span class="keyword">implements</span> <span class="title class_">FlutterActivityEvents</span>, Provider, PluginRegistry {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onCreate</span><span class="params">(Bundle savedInstanceState)</span> {</span><br><span class="line"> <span class="comment">// 设置全屏</span></span><br><span class="line"> <span class="keyword">if</span> (VERSION.SDK_INT >= <span class="number">21</span>) {</span><br><span class="line"> <span class="type">Window</span> <span class="variable">window</span> <span class="operator">=</span> <span class="built_in">this</span>.activity.getWindow();</span><br><span class="line"> window.addFlags(-<span class="number">2147483648</span>);</span><br><span class="line"> window.setStatusBarColor(<span class="number">1073741824</span>);</span><br><span class="line"> window.getDecorView().setSystemUiVisibility(<span class="number">1280</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 获取activity入参</span></span><br><span class="line"> String[] args = getArgsFromIntent(<span class="built_in">this</span>.activity.getIntent());</span><br><span class="line"> <span class="comment">// 确认Flutter Engine初始化完成,详细见后面</span></span><br><span class="line"> FlutterMain.ensureInitializationComplete(<span class="built_in">this</span>.activity.getApplicationContext(), args);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 创建FlutterView</span></span><br><span class="line"> </span><br><span class="line"> <span class="comment">// 这里实际上调用的是FlutterActivity或FlutterFragmentActivity中的createFlutterView,默认返回null</span></span><br><span class="line"> <span class="built_in">this</span>.flutterView = <span class="built_in">this</span>.viewFactory.createFlutterView(<span class="built_in">this</span>.activity); </span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">this</span>.flutterView == <span class="literal">null</span>) {</span><br><span class="line"> <span class="type">FlutterNativeView</span> <span class="variable">nativeView</span> <span class="operator">=</span> <span class="built_in">this</span>.viewFactory.createFlutterNativeView();</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 新建FlutterView</span></span><br><span class="line"> <span class="built_in">this</span>.flutterView = <span class="keyword">new</span> <span class="title class_">FlutterView</span>(<span class="built_in">this</span>.activity, (AttributeSet)<span class="literal">null</span>, nativeView);</span><br><span class="line"> <span class="built_in">this</span>.flutterView.setLayoutParams(matchParent);</span><br><span class="line"> <span class="comment">// activity 的ContentView设置为flutterView</span></span><br><span class="line"> <span class="built_in">this</span>.activity.setContentView(<span class="built_in">this</span>.flutterView);</span><br><span class="line"> <span class="comment">// 创建并添加launchView</span></span><br><span class="line"> <span class="built_in">this</span>.launchView = <span class="built_in">this</span>.createLaunchView();</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">this</span>.launchView != <span class="literal">null</span>) {</span><br><span class="line"> <span class="built_in">this</span>.addLaunchView();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 运行Flutter appBundle,也就是加载Flutter代码</span></span><br><span class="line"> <span class="keyword">if</span> (!<span class="built_in">this</span>.loadIntent(<span class="built_in">this</span>.activity.getIntent())) {</span><br><span class="line"> <span class="type">String</span> <span class="variable">appBundlePath</span> <span class="operator">=</span> FlutterMain.findAppBundlePath();</span><br><span class="line"> <span class="keyword">if</span> (appBundlePath != <span class="literal">null</span>) {</span><br><span class="line"> <span class="built_in">this</span>.runBundle(appBundlePath);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h5 id="FlutterView"><a href="#FlutterView" class="headerlink" title="FlutterView"></a>FlutterView</h5><p>FlutterView 是Flutter在Native上实际的绘制视图。</p>
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentStyleType="text/css" height="170px" preserveAspectRatio="none" style="width:493px;height:170px;background:#FFFFFF;" version="1.1" viewBox="0 0 493 170" width="493px" zoomAndPan="magnify"><defs/><g><!--MD5=[9e181a8feef4d879ff68ae341dac7e29]
class FlutterView--><g id="elem_FlutterView"><rect codeLine="1" fill="#F1F1F1" height="48" id="FlutterView" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="108" x="180" y="115"/><ellipse cx="195" cy="131" fill="#ADD1B2" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M197.9688,136.6406 Q197.3906,136.9375 196.75,137.0781 Q196.1094,137.2344 195.4063,137.2344 Q192.9063,137.2344 191.5781,135.5938 Q190.2656,133.9375 190.2656,130.8125 Q190.2656,127.6875 191.5781,126.0313 Q192.9063,124.375 195.4063,124.375 Q196.1094,124.375 196.75,124.5313 Q197.4063,124.6875 197.9688,124.9844 L197.9688,127.7031 Q197.3438,127.125 196.75,126.8594 Q196.1563,126.5781 195.5313,126.5781 Q194.1875,126.5781 193.5,127.6563 Q192.8125,128.7188 192.8125,130.8125 Q192.8125,132.9063 193.5,133.9844 Q194.1875,135.0469 195.5313,135.0469 Q196.1563,135.0469 196.75,134.7813 Q197.3438,134.5 197.9688,133.9219 L197.9688,136.6406 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="76" x="209" y="135.8467">FlutterView</text><line style="stroke:#181818;stroke-width:0.5;" x1="181" x2="287" y1="147" y2="147"/><line style="stroke:#181818;stroke-width:0.5;" x1="181" x2="287" y1="155" y2="155"/></g><!--MD5=[b8977a71577b55e49f7305cc373814dc]
class SurfaceView--><g id="elem_SurfaceView"><rect fill="#F1F1F1" height="48" id="SurfaceView" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="116" x="7" y="7"/><ellipse cx="22" cy="23" fill="#ADD1B2" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M24.9688,28.6406 Q24.3906,28.9375 23.75,29.0781 Q23.1094,29.2344 22.4063,29.2344 Q19.9063,29.2344 18.5781,27.5938 Q17.2656,25.9375 17.2656,22.8125 Q17.2656,19.6875 18.5781,18.0313 Q19.9063,16.375 22.4063,16.375 Q23.1094,16.375 23.75,16.5313 Q24.4063,16.6875 24.9688,16.9844 L24.9688,19.7031 Q24.3438,19.125 23.75,18.8594 Q23.1563,18.5781 22.5313,18.5781 Q21.1875,18.5781 20.5,19.6563 Q19.8125,20.7188 19.8125,22.8125 Q19.8125,24.9063 20.5,25.9844 Q21.1875,27.0469 22.5313,27.0469 Q23.1563,27.0469 23.75,26.7813 Q24.3438,26.5 24.9688,25.9219 L24.9688,28.6406 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="84" x="36" y="27.8467">SurfaceView</text><line style="stroke:#181818;stroke-width:0.5;" x1="8" x2="122" y1="39" y2="39"/><line style="stroke:#181818;stroke-width:0.5;" x1="8" x2="122" y1="47" y2="47"/></g><!--MD5=[3a7197b3f0da127a0a141acdd0964869]
class BinaryMessenger--><g id="elem_BinaryMessenger"><rect fill="#F1F1F1" height="48" id="BinaryMessenger" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="152" x="158" y="7"/><ellipse cx="173" cy="23" fill="#B4A7E5" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M168.9219,18.7656 L168.9219,16.6094 L176.3125,16.6094 L176.3125,18.7656 L173.8438,18.7656 L173.8438,26.8438 L176.3125,26.8438 L176.3125,29 L168.9219,29 L168.9219,26.8438 L171.3906,26.8438 L171.3906,18.7656 L168.9219,18.7656 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="120" x="187" y="27.8467">BinaryMessenger</text><line style="stroke:#181818;stroke-width:0.5;" x1="159" x2="309" y1="39" y2="39"/><line style="stroke:#181818;stroke-width:0.5;" x1="159" x2="309" y1="47" y2="47"/></g><!--MD5=[a9ae3d8e8cc3c991390b8b1661d0bc32]
class TextureRegistry--><g id="elem_TextureRegistry"><rect fill="#F1F1F1" height="48" id="TextureRegistry" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="141" x="345.5" y="7"/><ellipse cx="360.5" cy="23" fill="#B4A7E5" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M356.4219,18.7656 L356.4219,16.6094 L363.8125,16.6094 L363.8125,18.7656 L361.3438,18.7656 L361.3438,26.8438 L363.8125,26.8438 L363.8125,29 L356.4219,29 L356.4219,26.8438 L358.8906,26.8438 L358.8906,18.7656 L356.4219,18.7656 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" font-style="italic" lengthAdjust="spacing" textLength="109" x="374.5" y="27.8467">TextureRegistry</text><line style="stroke:#181818;stroke-width:0.5;" x1="346.5" x2="485.5" y1="39" y2="39"/><line style="stroke:#181818;stroke-width:0.5;" x1="346.5" x2="485.5" y1="47" y2="47"/></g><!--MD5=[50158a96695c75ded856f65154440c37]
reverse link SurfaceView to FlutterView--><g id="link_SurfaceView_FlutterView"><path d="M118.91,65.81 C144.42,81.81 174.22,100.51 197.11,114.86 " fill="none" id="SurfaceView-backto-FlutterView" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="none" points="114.89,71.56,101.67,55,122.33,59.7,114.89,71.56" style="stroke:#181818;stroke-width:1.0;"/></g><!--MD5=[c73a9ee65b4aa0ee47b390d463b97e16]
reverse link BinaryMessenger to FlutterView--><g id="link_BinaryMessenger_FlutterView"><path d="M234,75.02 C234,88.58 234,103.04 234,114.68 " fill="none" id="BinaryMessenger-backto-FlutterView" style="stroke:#181818;stroke-width:1.0;stroke-dasharray:7.0,7.0;"/><polygon fill="none" points="227,75,234,55,241,75,227,75" style="stroke:#181818;stroke-width:1.0;"/></g><!--MD5=[858cef43d89f070b3a95c1705d9fa863]
reverse link TextureRegistry to FlutterView--><g id="link_TextureRegistry_FlutterView"><path d="M359.13,65.12 C331.4,81.27 298.73,100.3 273.73,114.86 " fill="none" id="TextureRegistry-backto-FlutterView" style="stroke:#181818;stroke-width:1.0;stroke-dasharray:7.0,7.0;"/><polygon fill="none" points="355.7,59.02,376.51,55,362.75,71.11,355.7,59.02" style="stroke:#181818;stroke-width:1.0;"/></g><!--MD5=[9d438f640e58a11007dce4603888a18b]
@startuml
class FlutterView extends SurfaceView implements BinaryMessenger, TextureRegistry
@enduml
PlantUML version 1.2022.4(Sat Apr 09 13:29:17 UTC 2022)
(GPL source distribution)
Java Runtime: OpenJDK Runtime Environment
JVM: OpenJDK 64-Bit Server VM
Default Encoding: UTF-8
Language: en
Country: null
--></g></svg>
<p><code>BinaryMessenger</code> 是Flutter与Native同学的通道,后面会详细讲到<br><code>TextureRegistry</code> 用于管理SurfaceTexture</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">FlutterView</span> <span class="keyword">extends</span> <span class="title class_">SurfaceView</span> <span class="keyword">implements</span> <span class="title class_">BinaryMessenger</span>, TextureRegistry {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">FlutterView</span><span class="params">(Context context, AttributeSet attrs, FlutterNativeView nativeView)</span> {</span><br><span class="line"></span><br><span class="line"> </span><br><span class="line"> <span class="comment">// 创建FlutterNativeView</span></span><br><span class="line"> <span class="keyword">if</span> (nativeView == <span class="literal">null</span>) {</span><br><span class="line"> <span class="built_in">this</span>.mNativeView = <span class="keyword">new</span> <span class="title class_">FlutterNativeView</span>(activity.getApplicationContext());</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="built_in">this</span>.mNativeView = nativeView;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 设置dartExecutor</span></span><br><span class="line"> <span class="built_in">this</span>.dartExecutor = <span class="built_in">this</span>.mNativeView.getDartExecutor();</span><br><span class="line"> <span class="comment">// 设置flutterRenderer</span></span><br><span class="line"> <span class="built_in">this</span>.flutterRenderer = <span class="keyword">new</span> <span class="title class_">FlutterRenderer</span>(<span class="built_in">this</span>.mNativeView.getFlutterJNI());</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// 设置渲染和视图大小信息</span></span><br><span class="line"> <span class="built_in">this</span>.mIsSoftwareRenderingEnabled = FlutterJNI.nativeGetIsSoftwareRenderingEnabled();</span><br><span class="line"> <span class="built_in">this</span>.mMetrics = <span class="keyword">new</span> <span class="title class_">FlutterView</span>.ViewportMetrics();</span><br><span class="line"> <span class="built_in">this</span>.mMetrics.devicePixelRatio = context.getResources().getDisplayMetrics().density;</span><br><span class="line"> <span class="built_in">this</span>.setFocusable(<span class="literal">true</span>);</span><br><span class="line"> <span class="built_in">this</span>.setFocusableInTouchMode(<span class="literal">true</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// attachViewAndActivity</span></span><br><span class="line"> <span class="built_in">this</span>.mNativeView.attachViewAndActivity(<span class="built_in">this</span>, activity);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 设置SurfaceCallback</span></span><br><span class="line"> <span class="built_in">this</span>.mSurfaceCallback = <span class="keyword">new</span> <span class="title class_">Callback</span>() {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">surfaceCreated</span><span class="params">(SurfaceHolder holder)</span> {</span><br><span class="line"> FlutterView.<span class="built_in">this</span>.assertAttached();</span><br><span class="line"> FlutterView.<span class="built_in">this</span>.mNativeView.getFlutterJNI().onSurfaceCreated(holder.getSurface());</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">surfaceChanged</span><span class="params">(SurfaceHolder holder, <span class="type">int</span> format, <span class="type">int</span> width, <span class="type">int</span> height)</span> {</span><br><span class="line"> FlutterView.<span class="built_in">this</span>.assertAttached();</span><br><span class="line"> FlutterView.<span class="built_in">this</span>.mNativeView.getFlutterJNI().onSurfaceChanged(width, height);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">surfaceDestroyed</span><span class="params">(SurfaceHolder holder)</span> {</span><br><span class="line"> FlutterView.<span class="built_in">this</span>.assertAttached();</span><br><span class="line"> FlutterView.<span class="built_in">this</span>.mNativeView.getFlutterJNI().onSurfaceDestroyed();</span><br><span class="line"> }</span><br><span class="line"> };</span><br><span class="line"> <span class="built_in">this</span>.getHolder().addCallback(<span class="built_in">this</span>.mSurfaceCallback);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 设置内置Channel</span></span><br><span class="line"> <span class="built_in">this</span>.mActivityLifecycleListeners = <span class="keyword">new</span> <span class="title class_">ArrayList</span>();</span><br><span class="line"> <span class="built_in">this</span>.mFirstFrameListeners = <span class="keyword">new</span> <span class="title class_">ArrayList</span>();</span><br><span class="line"> <span class="built_in">this</span>.navigationChannel = <span class="keyword">new</span> <span class="title class_">NavigationChannel</span>(<span class="built_in">this</span>.dartExecutor);</span><br><span class="line"> <span class="built_in">this</span>.keyEventChannel = <span class="keyword">new</span> <span class="title class_">KeyEventChannel</span>(<span class="built_in">this</span>.dartExecutor);</span><br><span class="line"> <span class="built_in">this</span>.lifecycleChannel = <span class="keyword">new</span> <span class="title class_">LifecycleChannel</span>(<span class="built_in">this</span>.dartExecutor);</span><br><span class="line"> <span class="built_in">this</span>.localizationChannel = <span class="keyword">new</span> <span class="title class_">LocalizationChannel</span>(<span class="built_in">this</span>.dartExecutor);</span><br><span class="line"> <span class="built_in">this</span>.platformChannel = <span class="keyword">new</span> <span class="title class_">PlatformChannel</span>(<span class="built_in">this</span>.dartExecutor);</span><br><span class="line"> <span class="built_in">this</span>.systemChannel = <span class="keyword">new</span> <span class="title class_">SystemChannel</span>(<span class="built_in">this</span>.dartExecutor);</span><br><span class="line"> <span class="built_in">this</span>.settingsChannel = <span class="keyword">new</span> <span class="title class_">SettingsChannel</span>(<span class="built_in">this</span>.dartExecutor);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="keyword">final</span> <span class="type">PlatformPlugin</span> <span class="variable">platformPlugin</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">PlatformPlugin</span>(activity, <span class="built_in">this</span>.platformChannel);</span><br><span class="line"> <span class="built_in">this</span>.addActivityLifecycleListener(<span class="keyword">new</span> <span class="title class_">ActivityLifecycleListener</span>() {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onPostResume</span><span class="params">()</span> {</span><br><span class="line"> platformPlugin.updateSystemUiOverlays();</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"> <span class="built_in">this</span>.mImm = (InputMethodManager)<span class="built_in">this</span>.getContext().getSystemService(<span class="string">"input_method"</span>);</span><br><span class="line"> <span class="type">PlatformViewsController</span> <span class="variable">platformViewsController</span> <span class="operator">=</span> <span class="built_in">this</span>.mNativeView.getPluginRegistry().getPlatformViewsController();</span><br><span class="line"> <span class="built_in">this</span>.mTextInputPlugin = <span class="keyword">new</span> <span class="title class_">TextInputPlugin</span>(<span class="built_in">this</span>, <span class="built_in">this</span>.dartExecutor, platformViewsController);</span><br><span class="line"> <span class="built_in">this</span>.androidKeyProcessor = <span class="keyword">new</span> <span class="title class_">AndroidKeyProcessor</span>(<span class="built_in">this</span>.keyEventChannel, <span class="built_in">this</span>.mTextInputPlugin);</span><br><span class="line"> <span class="built_in">this</span>.androidTouchProcessor = <span class="keyword">new</span> <span class="title class_">AndroidTouchProcessor</span>(<span class="built_in">this</span>.flutterRenderer);</span><br><span class="line"> <span class="built_in">this</span>.mNativeView.getPluginRegistry().getPlatformViewsController().attachTextInputPlugin(<span class="built_in">this</span>.mTextInputPlugin);</span><br><span class="line"> <span class="built_in">this</span>.sendLocalesToDart(<span class="built_in">this</span>.getResources().getConfiguration());</span><br><span class="line"> <span class="built_in">this</span>.sendUserPlatformSettingsToDart();</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>在<code>FlutterActivityDelegate</code> 中我们知道,加载dart执行的是<code>FlutterView</code>的<code>runFromBundle</code>。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">runFromBundle</span><span class="params">(FlutterRunArguments args)</span> {</span><br><span class="line"> <span class="built_in">this</span>.assertAttached();</span><br><span class="line"> <span class="built_in">this</span>.preRun();</span><br><span class="line"> <span class="built_in">this</span>.mNativeView.runFromBundle(args);</span><br><span class="line"> <span class="built_in">this</span>.postRun();</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>实际上调用的是<code>mNativeView.runFromBundle(args)</code></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">FlutterNativeView</span> <span class="keyword">implements</span> <span class="title class_">BinaryMessenger</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">runFromBundle</span><span class="params">(FlutterRunArguments args)</span> {</span><br><span class="line"> <span class="keyword">if</span> (args.entrypoint == <span class="literal">null</span>) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">AssertionError</span>(<span class="string">"An entrypoint must be specified"</span>);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="built_in">this</span>.assertAttached();</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">this</span>.applicationIsRunning) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">AssertionError</span>(<span class="string">"This Flutter engine instance is already running an application"</span>);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="built_in">this</span>.mFlutterJNI.runBundleAndSnapshotFromLibrary(args.bundlePath, args.entrypoint, args.libraryPath, <span class="built_in">this</span>.mContext.getResources().getAssets());</span><br><span class="line"> <span class="built_in">this</span>.applicationIsRunning = <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>可以看到,最后调用的是mFlutterJNI。</p>
<h5 id="FlutterNativeView与FlutterJNI"><a href="#FlutterNativeView与FlutterJNI" class="headerlink" title="FlutterNativeView与FlutterJNI"></a>FlutterNativeView与FlutterJNI</h5><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">FlutterNativeView</span> <span class="keyword">implements</span> <span class="title class_">BinaryMessenger</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">FlutterNativeView</span><span class="params">(<span class="meta">@NonNull</span> Context context, <span class="type">boolean</span> isBackgroundView)</span> {</span><br><span class="line"> <span class="built_in">this</span>.mContext = context;</span><br><span class="line"> <span class="comment">// 创建FlutterPluginRegistry,插件注册器</span></span><br><span class="line"> <span class="built_in">this</span>.mPluginRegistry = <span class="keyword">new</span> <span class="title class_">FlutterPluginRegistry</span>(<span class="built_in">this</span>, context);</span><br><span class="line"> <span class="comment">// 创建FlutterJNI</span></span><br><span class="line"> <span class="built_in">this</span>.mFlutterJNI = <span class="keyword">new</span> <span class="title class_">FlutterJNI</span>();</span><br><span class="line"> <span class="comment">// 将</span></span><br><span class="line"> <span class="built_in">this</span>.mFlutterJNI.setRenderSurface(<span class="keyword">new</span> <span class="title class_">FlutterNativeView</span>.RenderSurfaceImpl());</span><br><span class="line"> <span class="comment">// 创建DartExecutor</span></span><br><span class="line"> <span class="built_in">this</span>.dartExecutor = <span class="keyword">new</span> <span class="title class_">DartExecutor</span>(<span class="built_in">this</span>.mFlutterJNI, context.getAssets());</span><br><span class="line"> <span class="comment">// addEngineLifecycleListener</span></span><br><span class="line"> <span class="built_in">this</span>.mFlutterJNI.addEngineLifecycleListener(<span class="keyword">new</span> <span class="title class_">FlutterNativeView</span>.EngineLifecycleListenerImpl());</span><br><span class="line"> <span class="built_in">this</span>.attach(<span class="built_in">this</span>, isBackgroundView);</span><br><span class="line"> <span class="built_in">this</span>.assertAttached();</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 加载Flutter Bundle</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">runFromBundle</span><span class="params">(FlutterRunArguments args)</span> {</span><br><span class="line"> <span class="keyword">if</span> (args.entrypoint == <span class="literal">null</span>) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">AssertionError</span>(<span class="string">"An entrypoint must be specified"</span>);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="built_in">this</span>.assertAttached();</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">this</span>.applicationIsRunning) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">AssertionError</span>(<span class="string">"This Flutter engine instance is already running an application"</span>);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="built_in">this</span>.mFlutterJNI.runBundleAndSnapshotFromLibrary(args.bundlePath, args.entrypoint, args.libraryPath, <span class="built_in">this</span>.mContext.getResources().getAssets());</span><br><span class="line"> <span class="built_in">this</span>.applicationIsRunning = <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h5 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h5><?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentStyleType="text/css" height="283px" preserveAspectRatio="none" style="width:882px;height:283px;background:#FFFFFF;" version="1.1" viewBox="0 0 882 283" width="882px" zoomAndPan="magnify"><defs/><g><ellipse cx="50" cy="41.5" fill="#222222" rx="10" ry="10" style="stroke:none;stroke-width:1.0;"/><rect fill="#F1F1F1" height="33.9688" rx="12.5" ry="12.5" style="stroke:#181818;stroke-width:0.5;" width="104" x="7" y="117"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="84" x="17" y="138.1387">FlutterActivity</text><rect fill="#F1F1F1" height="33.9688" rx="12.5" ry="12.5" style="stroke:#181818;stroke-width:0.5;" width="161" x="139.5" y="117"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="141" x="149.5" y="138.1387">FlutterActivityDelegate</text><g id="elem_GMN120"><path d="M80.5,6 L80.5,76.5313 A0,0 0 0 0 80.5,76.5313 L216,76.5313 L220,116.66 L224,76.5313 L359.5,76.5313 A0,0 0 0 0 359.5,76.5313 L359.5,16 L349.5,6 L80.5,6 A0,0 0 0 0 80.5,6 " fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><path d="M349.5,6 L349.5,16 L359.5,16 L349.5,6 " fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="195" x="90.5" y="23.0669">FlutterActivity 是主要承载页面,</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="249" x="86.5" y="38.1997">具体的实现由FlutterActivityDelegate代理</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="258" x="86.5" y="53.3325">FlutterActivityDelegate 创建FlutterView,</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="127" x="86.5" y="68.4653">并加载Flutter bundle</text></g><rect fill="#F1F1F1" height="33.9688" rx="12.5" ry="12.5" style="stroke:#181818;stroke-width:0.5;" width="89" x="336.5" y="117"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="69" x="346.5" y="138.1387">FlutterView</text><g id="elem_GMN125"><path d="M165.5,191 L165.5,276.6641 A0,0 0 0 0 165.5,276.6641 L510.5,276.6641 A0,0 0 0 0 510.5,276.6641 L510.5,201 L500.5,191 L360.43,191 L373.9,151.18 L352.43,191 L165.5,191 A0,0 0 0 0 165.5,191 " fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><path d="M500.5,191 L500.5,201 L510.5,201 L500.5,191 " fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="204" x="171.5" y="208.0669">FlutterView 继承于SurfaceView,</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="148" x="171.5" y="223.1997">为实际渲染的native view</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="239" x="171.5" y="238.3325">FlutterView初始化时会设置UI相关的信息</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="324" x="171.5" y="253.4653">以及内置的Channel,FlutterView与FlutterNativeView</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="52" x="171.5" y="268.5981">相互绑定</text></g><rect fill="#F1F1F1" height="33.9688" rx="12.5" ry="12.5" style="stroke:#181818;stroke-width:0.5;" width="128" x="454" y="117"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="108" x="464" y="138.1387">FlutterNativeView</text><g id="elem_GMN130"><path d="M380,14 L380,69.3984 A0,0 0 0 0 380,69.3984 L520.35,69.3984 L519.62,116.74 L528.35,69.3984 L674,69.3984 A0,0 0 0 0 674,69.3984 L674,24 L664,14 L380,14 A0,0 0 0 0 380,14 " fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><path d="M664,14 L664,24 L674,24 L664,14 " fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="273" x="386" y="31.0669">FlutterNativeView继承于BinaryMessenger,</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="254" x="386" y="46.1997">并持有FlutterJNI,而FlutterJNI是Android与</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="149" x="386" y="61.3325">FlutterEngine交互的桥梁</text></g><rect fill="#F1F1F1" height="33.9688" rx="12.5" ry="12.5" style="stroke:#181818;stroke-width:0.5;" width="76" x="645" y="117"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="56" x="655" y="138.1387">FlutterJNI</text><g id="elem_GMN136"><path d="M530.5,221.5 L530.5,246.6328 A0,0 0 0 0 530.5,246.6328 L835.5,246.6328 A0,0 0 0 0 835.5,246.6328 L835.5,231.5 L825.5,221.5 L687,221.5 L683,151.18 L679,221.5 L530.5,221.5 A0,0 0 0 0 530.5,221.5 " fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><path d="M825.5,221.5 L825.5,231.5 L835.5,231.5 L825.5,221.5 " fill="#FEFFDD" style="stroke:#181818;stroke-width:0.5;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="284" x="536.5" y="238.5669">大部分是jni的native方法,与Flutter Engine交互</text></g><ellipse cx="866" cy="234" fill="none" rx="10" ry="10" style="stroke:#222222;stroke-width:1.0;"/><ellipse cx="866.5" cy="234.5" fill="#222222" rx="6" ry="6" style="stroke:none;stroke-width:1.0;"/><!--MD5=[7f4335e1b6316eb72c8506d40a34e0c6]
link start to FlutterActivity--><g id="link_start_FlutterActivity"><path d="M50.9,51.51 C52.28,65.4 54.97,92.45 56.87,111.57 " fill="none" id="start-to-FlutterActivity" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="57.38,116.74,60.4859,107.3937,56.8938,111.7637,52.5238,108.1716,57.38,116.74" style="stroke:#181818;stroke-width:1.0;"/></g><!--MD5=[bdfed072028aaf26f53ff1a8514797ca]
link FlutterActivity to FlutterActivityDelegate--><g id="link_FlutterActivity_FlutterActivityDelegate"><path d="M111.2,134 C118.8,134 126.39,134 133.99,134 " fill="none" id="FlutterActivity-to-FlutterActivityDelegate" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="139.25,134,130.25,130,134.25,134,130.25,138,139.25,134" style="stroke:#181818;stroke-width:1.0;"/></g><!--MD5=[b4654c53f6a254be0eefc10f6e335199]
link FlutterActivityDelegate to FlutterView--><g id="link_FlutterActivityDelegate_FlutterView"><path d="M300.5,134 C310.77,134 321.04,134 331.31,134 " fill="none" id="FlutterActivityDelegate-to-FlutterView" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="336.35,134,327.35,130,331.35,134,327.35,138,336.35,134" style="stroke:#181818;stroke-width:1.0;"/></g><!--MD5=[3ef452a3bc4f7952a4b243a7afe0b223]
link FlutterView to FlutterNativeView--><g id="link_FlutterView_FlutterNativeView"><path d="M425.69,145.21 C433.3,146.19 440.92,146.71 448.54,146.75 " fill="none" id="FlutterView-to-FlutterNativeView" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="453.81,146.7,444.776,142.7773,448.8102,146.7429,444.8446,150.777,453.81,146.7" style="stroke:#181818;stroke-width:1.0;"/></g><!--MD5=[0f6a12f270cfc1587537e14268d245b0]
link FlutterNativeView to FlutterView--><g id="link_FlutterNativeView_FlutterView"><path d="M453.81,121.3 C446.19,121.12 438.58,121.42 430.96,122.18 " fill="none" id="FlutterNativeView-to-FlutterView" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="425.69,122.79,435.0879,125.7361,430.6573,122.219,434.1744,117.7884,425.69,122.79" style="stroke:#181818;stroke-width:1.0;"/></g><!--MD5=[aea36ecdc750e134d8d4d13f3f0ef1f3]
link FlutterNativeView to FlutterJNI--><g id="link_FlutterNativeView_FlutterJNI"><path d="M582.13,134 C601.22,134 620.31,134 639.4,134 " fill="none" id="FlutterNativeView-to-FlutterJNI" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="644.78,134,635.78,130,639.78,134,635.78,138,644.78,134" style="stroke:#181818;stroke-width:1.0;"/></g><!--MD5=[0610f192158a662c333784acf518a884]
link FlutterJNI to end--><g id="link_FlutterJNI_end"><path d="M721.21,139.55 C757.25,145.66 810.84,159.62 846,191 C854.26,198.37 859.41,209.89 862.41,219.01 " fill="none" id="FlutterJNI-to-end" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="863.94,224.04,865.1451,214.2651,862.4836,219.2568,857.492,216.5953,863.94,224.04" style="stroke:#181818;stroke-width:1.0;"/></g><!--MD5=[35a1c22b6583565d98070e025d742655]
@startuml
(*) - -> FlutterActivity
"FlutterActivity" -> "FlutterActivityDelegate"
note top
FlutterActivity 是主要承载页面,
具体的实现由FlutterActivityDelegate代理
FlutterActivityDelegate 创建FlutterView,
并加载Flutter bundle
end note
FlutterActivityDelegate -> FlutterView
note bottom
FlutterView 继承于SurfaceView,
为实际渲染的native view
FlutterView初始化时会设置UI相关的信息
以及内置的Channel,FlutterView与FlutterNativeView
相互绑定
end note
FlutterView -> FlutterNativeView
note top
FlutterNativeView继承于BinaryMessenger,
并持有FlutterJNI,而FlutterJNI是Android与
FlutterEngine交互的桥梁
end note
FlutterNativeView -> FlutterView
FlutterNativeView -> FlutterJNI
note bottom
大部分是jni的native方法,与Flutter Engine交互
end note
- ->(*)
@enduml
PlantUML version 1.2022.4(Sat Apr 09 13:29:17 UTC 2022)
(GPL source distribution)
Java Runtime: OpenJDK Runtime Environment
JVM: OpenJDK 64-Bit Server VM
Default Encoding: UTF-8
Language: en
Country: null
--></g></svg>
<h4 id="Flutter-Engine"><a href="#Flutter-Engine" class="headerlink" title="Flutter Engine"></a>Flutter Engine</h4><h5 id="Flutter-初始化"><a href="#Flutter-初始化" class="headerlink" title="Flutter 初始化"></a>Flutter 初始化</h5><p>在使用Flutter前需要初始化Flutter</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">FlutterMain.startInitialization(applicationContext);</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">FlutterMain</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">startInitialization</span><span class="params">(<span class="meta">@NonNull</span> Context applicationContext)</span> {</span><br><span class="line"> <span class="keyword">if</span> (!isRunningInRobolectricTest) {</span><br><span class="line"> startInitialization(applicationContext, <span class="keyword">new</span> <span class="title class_">FlutterMain</span>.Settings());</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">startInitialization</span><span class="params">(<span class="meta">@NonNull</span> Context applicationContext, <span class="meta">@NonNull</span> FlutterMain.Settings settings)</span> {</span><br><span class="line"> <span class="keyword">if</span> (!isRunningInRobolectricTest) {</span><br><span class="line"> <span class="comment">// 初始化必须在主线程</span></span><br><span class="line"> <span class="keyword">if</span> (Looper.myLooper() != Looper.getMainLooper()) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalStateException</span>(<span class="string">"startInitialization must be called on the main thread"</span>);</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (sSettings == <span class="literal">null</span>) {</span><br><span class="line"> sSettings = settings;</span><br><span class="line"> <span class="type">long</span> <span class="variable">initStartTimestampMillis</span> <span class="operator">=</span> SystemClock.uptimeMillis();</span><br><span class="line"> <span class="comment">// 初始化配置,主要是读取metadata中自定义的libapp.so、flutter_assets、vm_snapshot_data和isolate_snapshot_data对于的路径</span></span><br><span class="line"> <span class="comment">// 一般可以不是自行设置</span></span><br><span class="line"> initConfig(applicationContext);</span><br><span class="line"> <span class="comment">// 初始化Flutter资源,从flutter_assets读取并加载资源</span></span><br><span class="line"> <span class="comment">// 包含vm_snapshot_data,isolate_snapshot_data、kernel_blob.bin</span></span><br><span class="line"> initResources(applicationContext);</span><br><span class="line"> <span class="comment">// 记载flutter.so</span></span><br><span class="line"> System.loadLibrary(<span class="string">"flutter"</span>);</span><br><span class="line"> <span class="comment">// 初始化Vsync工具</span></span><br><span class="line"> VsyncWaiter.getInstance((WindowManager)applicationContext.getSystemService(<span class="string">"window"</span>)).init();</span><br><span class="line"> <span class="comment">// 记录初始化耗时</span></span><br><span class="line"> <span class="type">long</span> <span class="variable">initTimeMillis</span> <span class="operator">=</span> SystemClock.uptimeMillis() - initStartTimestampMillis;</span><br><span class="line"> FlutterJNI.nativeRecordStartTimestamp(initTimeMillis);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>android assets目录下flutter_assets</p>
<figure class="highlight txt"><table><tr><td class="code"><pre><span class="line">assets</span><br><span class="line">└── flutter_assets</span><br><span class="line"> ├── AssetManifest.json</span><br><span class="line"> ├── FontManifest.json</span><br><span class="line"> ├── LICENSE</span><br><span class="line"> ├── fonts</span><br><span class="line"> │ └── MaterialIcons-Regular.ttf</span><br><span class="line"> ├── isolate_snapshot_data</span><br><span class="line"> ├── kernel_blob.bin</span><br><span class="line"> ├── packages</span><br><span class="line"> │ └── cupertino_icons</span><br><span class="line"> │ └── assets</span><br><span class="line"> │ └── CupertinoIcons.ttf</span><br><span class="line"> └── vm_snapshot_data</span><br></pre></td></tr></table></figure>
<p>在<code>FlutterActivityDelegate</code>中,<code>onCreate</code>时,</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">class</span> <span class="title class_">FlutterActivityDelegate</span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onCreate</span><span class="params">(Bundle savedInstanceState)</span> {</span><br><span class="line"> FlutterMain.ensureInitializationComplete(<span class="built_in">this</span>.activity.getApplicationContext(), args);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">FlutterMain</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">ensureInitializationComplete</span><span class="params">(<span class="meta">@NonNull</span> Context applicationContext, <span class="meta">@Nullable</span> String[] args)</span> {</span><br><span class="line"> <span class="keyword">if</span> (!isRunningInRobolectricTest) {</span><br><span class="line"> <span class="comment">// 确认在主线程,且sSettings不为空,sSettings在startInitialization中设置</span></span><br><span class="line"> <span class="keyword">if</span> (Looper.myLooper() != Looper.getMainLooper()) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalStateException</span>(<span class="string">"ensureInitializationComplete must be called on the main thread"</span>);</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (sSettings == <span class="literal">null</span>) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalStateException</span>(<span class="string">"ensureInitializationComplete must be called after startInitialization"</span>);</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (!sInitialized) {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 等待资源加载完成,在startInitialization中设置</span></span><br><span class="line"> <span class="keyword">if</span> (sResourceExtractor != <span class="literal">null</span>) {</span><br><span class="line"> sResourceExtractor.waitForCompletion();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 设置flutter参数</span></span><br><span class="line"> <span class="comment">// icu-symbol-prefix, icu-native-lib-path,snapshot-asset-path,</span></span><br><span class="line"> <span class="comment">// vm-snapshot-data,isolate-snapshot-data,cache-dir-path,log-tag</span></span><br><span class="line"> List<String> shellArgs = <span class="keyword">new</span> <span class="title class_">ArrayList</span>();</span><br><span class="line"> shellArgs.add(<span class="string">"--icu-symbol-prefix=_binary_icudtl_dat"</span>);</span><br><span class="line"> <span class="type">ApplicationInfo</span> <span class="variable">applicationInfo</span> <span class="operator">=</span> getApplicationInfo(applicationContext);</span><br><span class="line"> shellArgs.add(<span class="string">"--icu-native-lib-path="</span> + applicationInfo.nativeLibraryDir + File.separator + <span class="string">"libflutter.so"</span>);</span><br><span class="line"> <span class="keyword">if</span> (args != <span class="literal">null</span>) {</span><br><span class="line"> Collections.addAll(shellArgs, args);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="type">String</span> <span class="variable">kernelPath</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line"> <span class="type">String</span> <span class="variable">appStoragePath</span> <span class="operator">=</span> PathUtils.getDataDirectory(applicationContext) + File.separator + sFlutterAssetsDir;</span><br><span class="line"> kernelPath = appStoragePath + File.separator + <span class="string">"kernel_blob.bin"</span>;</span><br><span class="line"> shellArgs.add(<span class="string">"--snapshot-asset-path="</span> + appStoragePath);</span><br><span class="line"> shellArgs.add(<span class="string">"--vm-snapshot-data="</span> + sVmSnapshotData);</span><br><span class="line"> shellArgs.add(<span class="string">"--isolate-snapshot-data="</span> + sIsolateSnapshotData);</span><br><span class="line"> shellArgs.add(<span class="string">"--cache-dir-path="</span> + PathUtils.getCacheDirectory(applicationContext));</span><br><span class="line"> <span class="keyword">if</span> (sSettings.getLogTag() != <span class="literal">null</span>) {</span><br><span class="line"> shellArgs.add(<span class="string">"--log-tag="</span> + sSettings.getLogTag());</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> appStoragePath = PathUtils.getFilesDir(applicationContext);</span><br><span class="line"> <span class="type">String</span> <span class="variable">engineCachesPath</span> <span class="operator">=</span> PathUtils.getCacheDirectory(applicationContext);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// FlutterJNI 初始化Flutter Engine</span></span><br><span class="line"> FlutterJNI.nativeInit(applicationContext, (String[])shellArgs.toArray(<span class="keyword">new</span> <span class="title class_">String</span>[<span class="number">0</span>]), kernelPath, appStoragePath, engineCachesPath);</span><br><span class="line"> sInitialized = <span class="literal">true</span>;</span><br><span class="line"> } <span class="keyword">catch</span> (Exception var7) {</span><br><span class="line"> Log.e(<span class="string">"FlutterMain"</span>, <span class="string">"Flutter initialization failed."</span>, var7);</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">RuntimeException</span>(var7);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>可以看到,所有与Flutter Engine相关的操作都是用过FlutterJNI来交互的</p>
<h4 id="小结-1"><a href="#小结-1" class="headerlink" title="小结"></a>小结</h4><p>Flutter Engine初始化主要是加载<code>flutter.so</code>,设置<code>flutter_assets</code>,并通过FlutterJNI设置到Flutter Engine中。</p>
<p>关于FlutterJNI相关的内容,再后面关于Flutter Engine定制中会详细介绍到。</p>
]]></content>
</entry>
<entry>
<title>Flutter 基本使用</title>
<url>/2020/02/06/Flutter-%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8/</url>
<content><![CDATA[<h3 id="一、-Flutter-混合开发"><a href="#一、-Flutter-混合开发" class="headerlink" title="一、 Flutter 混合开发"></a>一、 Flutter 混合开发</h3><p>Flutter 环境配置</p>
<h4 id="1-Flutter-整体架构"><a href="#1-Flutter-整体架构" class="headerlink" title="1. Flutter 整体架构"></a>1. Flutter 整体架构</h4><p><img src="https://raw.githubusercontent.com/zauther/figurebed/blog/images/flutter.svg" alt="flutter"></p>
<span id="more"></span>
<h4 id="2-Flutter-开发环境配置"><a href="#2-Flutter-开发环境配置" class="headerlink" title="2. Flutter 开发环境配置"></a>2. Flutter 开发环境配置</h4><p>Flutter环境</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash"><span class="built_in">cd</span> ~/development</span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">unzip ~/Downloads/flutter_macos_v1.9.1+hotfix.4-stable.zip</span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash"><span class="built_in">export</span> PATH=<span class="string">"<span class="variable">$PATH</span>:`pwd`/flutter/bin"</span></span></span><br></pre></td></tr></table></figure>
<p>Android SDK</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash"><span class="built_in">export</span> ANDROID_HOME=/Users/*/Library/Android/sdk</span></span><br></pre></td></tr></table></figure>
<p>Xcode 安装</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer</span></span><br></pre></td></tr></table></figure>
<h4 id="3-Flutter-常用命令"><a href="#3-Flutter-常用命令" class="headerlink" title="3. Flutter 常用命令"></a>3. Flutter 常用命令</h4><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">#</span><span class="language-bash"><span class="comment"># flutter 环境诊断</span></span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">flutter doctor</span> </span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash"><span class="comment"># flutter 版本切换</span></span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">flutter version v1.5.4-hotfix.2</span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash"><span class="comment"># flutter 创建工程模板</span></span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">flutter create --org com.exemple --template=[plugin,app,package,module] projectname</span></span><br></pre></td></tr></table></figure>
<h4 id="4-Flutter接入及原理"><a href="#4-Flutter接入及原理" class="headerlink" title="4. Flutter接入及原理"></a>4. Flutter接入及原理</h4><p>Flutter开发方式,目前有4种,分别是:纯的Dart库开发、Flutter应用开发、Flutter插件开发以及Flutter Module接入。下面,分别对这4种开发形式做一个介绍。</p>
<h5 id="4-1-纯的Dart库开发"><a href="#4-1-纯的Dart库开发" class="headerlink" title="4.1 纯的Dart库开发"></a>4.1 纯的Dart库开发</h5><p>纯的Dart库开发,无客户端相关Native代码,通过命令行生成工程模板:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">flutter create --org com.exemple --template=package somepackage</span></span><br></pre></td></tr></table></figure>
<img src="https://raw.githubusercontent.com/zauther/figurebed/blog/images/20200209195127.png" alt="image-20191024191219392" style="zoom:50%;" />
<h5 id="4-2-Flutter应用开发"><a href="#4-2-Flutter应用开发" class="headerlink" title="4.2 Flutter应用开发"></a>4.2 Flutter应用开发</h5><p>Flutter应用开发,可直接运行,适合开发新的APP。</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">flutter create --org com.exemple --template=app someapp</span></span><br></pre></td></tr></table></figure>
<p>从目录结构可以看出,此工程中有3个目录:android、ios、lib,android目录下是与Android平台相关的代码及配置,ios目录下是与iOS平台相关的代码及配置,lib目录下为flutter平台相关的代码。</p>
<p>pubspec.yaml为flutter工程相关的配置,包含依赖的插件、资源等。.flutter-plugins 文件为flutter插件路径映射文件。</p>
<p>我们以Android开发者的角度,简单看一下,Flutter是如何被引入到Android项目中的。</p>
<p>在Android工程中 <code>settings.gralde</code> 文件中,我们可以看到,主要做了以下几件事情:</p>
<figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line">include <span class="string">':app'</span> </span><br><span class="line"><span class="keyword">def</span> flutterProjectRoot = rootProject.projectDir.parentFile.toPath()</span><br><span class="line"><span class="keyword">def</span> plugins = <span class="keyword">new</span> Properties()</span><br><span class="line"><span class="keyword">def</span> pluginsFile = <span class="keyword">new</span> File(flutterProjectRoot.toFile(), <span class="string">'.flutter-plugins'</span>)</span><br><span class="line"><span class="keyword">if</span> (pluginsFile.exists()) {</span><br><span class="line"> pluginsFile.withReader(<span class="string">'UTF-8'</span>) { reader -> plugins.load(reader) }</span><br><span class="line">}</span><br><span class="line">plugins.each { name, path -></span><br><span class="line"> <span class="keyword">def</span> pluginDirectory = flutterProjectRoot.resolve(path).resolve(<span class="string">'android'</span>).toFile()</span><br><span class="line"> include <span class="string">":$name"</span></span><br><span class="line"> project(<span class="string">":$name"</span>).projectDir = pluginDirectory</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<ol>
<li>寻找<code>.flutter-plugins</code> 文件并读取配置</li>
<li>将<code>.flutter-plugins</code>配置中的库引入工程中</li>
</ol>
<p><code>.flutter-plugins</code> 中的内容:</p>
<figure class="highlight txt"><table><tr><td class="code"><pre><span class="line">flutter_boost=/Users/zauther/.pub-cache/hosted/pub.flutter-io.cn/flutter_boost-0.1.54/</span><br><span class="line">xservice_kit=/Users/zauther/.pub-cache/hosted/pub.flutter-io.cn/xservice_kit-0.0.29/</span><br></pre></td></tr></table></figure>
<p>在app对应的 <code>build.gradle</code> 文件中,前面的配置代码:</p>
<figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line"><span class="keyword">def</span> localProperties = <span class="keyword">new</span> Properties()</span><br><span class="line"><span class="keyword">def</span> localPropertiesFile = rootProject.file(<span class="string">'local.properties'</span>)</span><br><span class="line"><span class="keyword">if</span> (localPropertiesFile.exists()) {</span><br><span class="line"> localPropertiesFile.withReader(<span class="string">'UTF-8'</span>) { reader -></span><br><span class="line"> localProperties.load(reader)</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> flutterRoot = localProperties.getProperty(<span class="string">'flutter.sdk'</span>)</span><br><span class="line"><span class="keyword">if</span> (flutterRoot == <span class="literal">null</span>) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> GradleException(<span class="string">"Flutter SDK not found. Define location with flutter.sdk in the local.properties file."</span>)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> flutterVersionCode = localProperties.getProperty(<span class="string">'flutter.versionCode'</span>)</span><br><span class="line"><span class="keyword">if</span> (flutterVersionCode == <span class="literal">null</span>) {</span><br><span class="line"> flutterVersionCode = <span class="string">'1'</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> flutterVersionName = localProperties.getProperty(<span class="string">'flutter.versionName'</span>)</span><br><span class="line"><span class="keyword">if</span> (flutterVersionName == <span class="literal">null</span>) {</span><br><span class="line"> flutterVersionName = <span class="string">'1.0'</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">apply <span class="attr">plugin:</span> <span class="string">'com.android.application'</span></span><br><span class="line">apply <span class="attr">from:</span> <span class="string">"$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"</span></span><br><span class="line">......</span><br><span class="line">flutter {</span><br><span class="line"> source <span class="string">'../..'</span></span><br><span class="line">}</span><br><span class="line">......</span><br></pre></td></tr></table></figure>
<p>可以看出主要做了一下几件事:</p>
<ol>
<li>读取 <code>local.properties</code> 配置</li>
<li>从配置中读取flutter.sdk、flutter.versionCode、flutter.versionName</li>
<li>通过flutter.sdk路径找到 <code>flutter.gradle</code> ,此文件即为flutter编译流程文件,后面单独介绍</li>
<li>设置flutter对应的lib所在目录,lib中包含flutter代码入口 <code>main.dart</code></li>
</ol>
<h5 id="4-3-Flutter-插件开发"><a href="#4-3-Flutter-插件开发" class="headerlink" title="4.3 Flutter 插件开发"></a>4.3 Flutter 插件开发</h5><p>Flutter插件类似于Java开发过程中的库,可在目前项目上直接引入已有功能。</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">flutter create --org com.exemple --template=plugin someplugin</span></span><br></pre></td></tr></table></figure>
<img src="https://raw.githubusercontent.com/zauther/figurebed/blog/images/20200209195909.png" alt="image-20191019005837181" style="zoom:50%;" />
<p>目录结构同Flutter应用,其中example模块为一个独立的flutter 工程,可用于测试插件。通过这个例子,以Android开发者视角,来看一下插件是插件如何编写以及被引入的。</p>
<p>Flutter与Native的通讯分为2种:一是Flutter主动调用Native,并获取Native的返回结果;二是Native主动调用Flutter,并获取Flutter返回结果。</p>
<h6 id="Flutter调用Native"><a href="#Flutter调用Native" class="headerlink" title="Flutter调用Native"></a>Flutter调用Native</h6><p>在flutter插件的android目录下,新建类Testflutterplugin2Plugin,实现MethodCallHandler接口:</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">/** Testflutterplugin2Plugin */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Testflutterplugin2Plugin</span> <span class="keyword">implements</span> <span class="title class_">MethodCallHandler</span> {</span><br><span class="line"> <span class="comment">/** Plugin registration. */</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">registerWith</span><span class="params">(Registrar registrar)</span> {</span><br><span class="line"> <span class="keyword">final</span> <span class="type">MethodChannel</span> <span class="variable">channel</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">MethodChannel</span>(registrar.messenger(), <span class="string">"testflutterplugin2"</span>);</span><br><span class="line"> channel.setMethodCallHandler(<span class="keyword">new</span> <span class="title class_">Testflutterplugin2Plugin</span>());</span><br><span class="line"> }</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onMethodCall</span><span class="params">(MethodCall call, Result result)</span> {</span><br><span class="line"> <span class="keyword">if</span> (call.method.equals(<span class="string">"getPlatformVersion"</span>)) {</span><br><span class="line"> result.success(<span class="string">"Android "</span> + android.os.Build.VERSION.RELEASE);</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span>(call.method.equals(<span class="string">"FUNC"</span>)){</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="comment">// do something</span></span><br><span class="line"> result.success(<span class="string">"do something"</span>);</span><br><span class="line"> }<span class="keyword">catch</span> (Exception e){</span><br><span class="line"> <span class="comment">// catch error</span></span><br><span class="line"> result.error(<span class="string">"ERROR"</span>,<span class="string">"do something error"</span>,<span class="literal">null</span>);</span><br><span class="line"> }</span><br><span class="line"> }<span class="keyword">else</span> {</span><br><span class="line"> result.notImplemented();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>方法registerWith中,通过Registrar创建MethodChannel,并将Testflutterplugin2Plugin加入到MethodChannel中。</p>
<p>在onMethodCall方法中,参数MethodCall包含有Flutter调用的方法名以及传入参数,Result对象用于返回Native的处理结果给Flutter。</p>
<p>在Flutter代码中: </p>
<figure class="highlight dart"><table><tr><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Testflutterplugin2</span> </span>{</span><br><span class="line"> <span class="keyword">static</span> <span class="keyword">const</span> MethodChannel _channel =</span><br><span class="line"> <span class="keyword">const</span> MethodChannel(<span class="string">'testflutterplugin2'</span>);</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">static</span> Future<<span class="built_in">String</span>> <span class="keyword">get</span> platformVersion <span class="keyword">async</span> {</span><br><span class="line"> <span class="keyword">final</span> <span class="built_in">String</span> version = <span class="keyword">await</span> _channel.invokeMethod(<span class="string">'getPlatformVersion'</span>);</span><br><span class="line"> <span class="keyword">return</span> version;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h6 id="Native调用Flutter"><a href="#Native调用Flutter" class="headerlink" title="Native调用Flutter"></a>Native调用Flutter</h6><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Testflutterplugin2EventChannel</span> <span class="keyword">implements</span> <span class="title class_">EventChannel</span>.StreamHandler {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">registerWith</span><span class="params">(PluginRegistry.Registrar registrar)</span> {</span><br><span class="line"> <span class="keyword">final</span> <span class="type">EventChannel</span> <span class="variable">channel</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">EventChannel</span>(registrar.messenger(), <span class="string">"testflutterplugin2.eventchannel"</span>);</span><br><span class="line"> channel.setStreamHandler(<span class="keyword">new</span> <span class="title class_">Testflutterplugin2EventChannel</span>());</span><br><span class="line"> }</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onListen</span><span class="params">(Object arguments, EventChannel.EventSink eventSink)</span> {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> eventSink.success(<span class="string">"success"</span>);</span><br><span class="line"> } <span class="keyword">catch</span> (Exception e) {</span><br><span class="line"> eventSink.error(<span class="string">"error"</span>, <span class="string">"Testflutterplugin2EventChannel error"</span>, <span class="literal">null</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onCancel</span><span class="params">(Object arguments)</span> {</span><br><span class="line"> </span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<figure class="highlight dart"><table><tr><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Testflutterplugin2EventChannel</span> </span>{</span><br><span class="line"> <span class="keyword">static</span> <span class="keyword">const</span> EventChannel _eventChannel =</span><br><span class="line"> <span class="keyword">const</span> EventChannel(<span class="string">'testflutterplugin2.eventchannel'</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">static</span> <span class="keyword">void</span> test() {</span><br><span class="line"> _eventChannel.receiveBroadcastStream(<span class="string">'arguments'</span>).listen((result) {},</span><br><span class="line"> onError: (e) {}, onDone: () {}, cancelOnError: <span class="keyword">true</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">static</span> <span class="keyword">void</span> test1() {</span><br><span class="line"> _eventChannel.receiveBroadcastStream().listen((result) {},</span><br><span class="line"> onError: (e) {}, onDone: () {}, cancelOnError: <span class="keyword">true</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h5 id="Android平台下的插件引入"><a href="#Android平台下的插件引入" class="headerlink" title="Android平台下的插件引入"></a>Android平台下的插件引入</h5><p>Android目录中的代码为Android与Flutter桥接的部分:</p>
<p>在<code>settings.gradle</code>中 <code>rootProject.name = 'testflutterplugin2'</code> 只是声明了Android模块,<code>build.gralde</code> 中为Android相关的配置项。</p>
<h5 id="插件代码"><a href="#插件代码" class="headerlink" title="插件代码"></a>插件代码</h5><p>插件实现了<code>MethodCallHandler</code> 接口,实现了<code>onMethodCall</code> 方法。</p>
<p><code>registerWith</code> 方法中:通过传入的Registrar对象,新建MethodChannel,并指定其名<code>testflutterplugin2</code>。</p>
<p>设置MethodChannel的处理方法Testflutterplugin2Plugin。这段代码主要作用用于注册处理方法Testflutterplugin2Plugin到Registrar。而MethodChannel只是对这个注册过程的一个封装。</p>
<p>查看MethodChannel核心代码:</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setMethodCallHandler</span><span class="params">(<span class="meta">@Nullable</span> MethodChannel.MethodCallHandler handler)</span> {</span><br><span class="line"> <span class="built_in">this</span>.messenger.setMessageHandler(<span class="built_in">this</span>.name, handler == <span class="literal">null</span> ? <span class="literal">null</span> : <span class="keyword">new</span> <span class="title class_">MethodChannel</span>.IncomingMethodCallHandler(handler));</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<p>在实现MethodCallHandler接口的类中,对于onMethodCall方法:</p>
<p>MethodCall对象中包含了来自于Flutter的调用方法名和参数信息。其中,arguments为Map对象或JSONObject</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> String method;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> Object arguments;</span><br></pre></td></tr></table></figure>
<p>Result接口中包含Native端的返回给Flutter测的结果信息。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onMessage</span><span class="params">(ByteBuffer message, <span class="keyword">final</span> BinaryReply reply)</span> {</span><br><span class="line"> <span class="type">MethodCall</span> <span class="variable">call</span> <span class="operator">=</span> MethodChannel.<span class="built_in">this</span>.codec.decodeMethodCall(message);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="built_in">this</span>.handler.onMethodCall(call, <span class="keyword">new</span> <span class="title class_">MethodChannel</span>.Result() {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">success</span><span class="params">(Object result)</span> {</span><br><span class="line"> reply.reply(MethodChannel.<span class="built_in">this</span>.codec.encodeSuccessEnvelope(result));</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">error</span><span class="params">(String errorCode, String errorMessage, Object errorDetails)</span> {</span><br><span class="line"> reply.reply(MethodChannel.<span class="built_in">this</span>.codec.encodeErrorEnvelope(errorCode, errorMessage, errorDetails));</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">notImplemented</span><span class="params">()</span> {</span><br><span class="line"> reply.reply((ByteBuffer)<span class="literal">null</span>);</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"> } <span class="keyword">catch</span> (RuntimeException var5) {</span><br><span class="line"> Log.e(<span class="string">"MethodChannel#"</span> + MethodChannel.<span class="built_in">this</span>.name, <span class="string">"Failed to handle method call"</span>, var5);</span><br><span class="line"> reply.reply(MethodChannel.<span class="built_in">this</span>.codec.encodeErrorEnvelope(<span class="string">"error"</span>, var5.getMessage(), (Object)<span class="literal">null</span>));</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>在IncomingResultHandler中,Result的匿名内部类中,通过BinaryReply将Native端的处理结果经StandardMethodCodec类,编码后传递给Flutter侧。</p>
<h5 id="插件的引入"><a href="#插件的引入" class="headerlink" title="插件的引入"></a>插件的引入</h5><p>在example模块中,在<code>MainActivity.java</code> 的<code>onCreate</code> 中:</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MainActivity</span> <span class="keyword">extends</span> <span class="title class_">FlutterActivity</span> {</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">onCreate</span><span class="params">(Bundle savedInstanceState)</span> {</span><br><span class="line"> <span class="built_in">super</span>.onCreate(savedInstanceState);</span><br><span class="line"> GeneratedPluginRegistrant.registerWith(<span class="built_in">this</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Generated file. Do not edit.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">class</span> <span class="title class_">GeneratedPluginRegistrant</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">registerWith</span><span class="params">(PluginRegistry registry)</span> {</span><br><span class="line"> <span class="keyword">if</span> (alreadyRegisteredWith(registry)) {</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> Testflutterplugin2Plugin.registerWith(registry.registrarFor(<span class="string">"cn.cwiki.flutter.test.testflutterplugin2.Testflutterplugin2Plugin"</span>));</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="type">boolean</span> <span class="title function_">alreadyRegisteredWith</span><span class="params">(PluginRegistry registry)</span> {</span><br><span class="line"> <span class="keyword">final</span> <span class="type">String</span> <span class="variable">key</span> <span class="operator">=</span> GeneratedPluginRegistrant.class.getCanonicalName();</span><br><span class="line"> <span class="keyword">if</span> (registry.hasPlugin(key)) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"> registry.registrarFor(key);</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<figure class="highlight xml"><table><tr><td class="code"><pre><span class="line"><span class="tag"><<span class="name">application</span></span></span><br><span class="line"><span class="tag"> <span class="attr">android:name</span>=<span class="string">"io.flutter.app.FlutterApplication"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">android:label</span>=<span class="string">"testflutterplugin2_example"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">android:icon</span>=<span class="string">"@mipmap/ic_launcher"</span>></span></span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">FlutterApplication</span> <span class="keyword">extends</span> <span class="title class_">Application</span> {</span><br><span class="line"> <span class="keyword">private</span> <span class="type">Activity</span> <span class="variable">mCurrentActivity</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">FlutterApplication</span><span class="params">()</span> {</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@CallSuper</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onCreate</span><span class="params">()</span> {</span><br><span class="line"> <span class="built_in">super</span>.onCreate();</span><br><span class="line"> FlutterMain.startInitialization(<span class="built_in">this</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> Activity <span class="title function_">getCurrentActivity</span><span class="params">()</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">this</span>.mCurrentActivity;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setCurrentActivity</span><span class="params">(Activity mCurrentActivity)</span> {</span><br><span class="line"> <span class="built_in">this</span>.mCurrentActivity = mCurrentActivity;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>FlutterApplication中核心作用是<code> FlutterMain.startInitialization(this);</code> 初始化Flutter框架</p>
<h3 id="新建Flutter-Module"><a href="#新建Flutter-Module" class="headerlink" title="新建Flutter Module"></a>新建Flutter Module</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">flutter create --org com.exemple --template=plugin somemodule</span></span><br></pre></td></tr></table></figure>
<img src="https://raw.githubusercontent.com/zauther/figurebed/blog/images/20200209200427.png" alt="image-20191020105011609" style="zoom:50%;" />
<p>settings.gradle</p>
<figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line">include <span class="string">':app'</span></span><br><span class="line"></span><br><span class="line">rootProject.name = <span class="string">'android_generated'</span></span><br><span class="line">setBinding(<span class="keyword">new</span> Binding([<span class="attr">gradle:</span> <span class="variable language_">this</span>]))</span><br><span class="line">evaluate(<span class="keyword">new</span> File(<span class="string">'include_flutter.groovy'</span>))</span><br></pre></td></tr></table></figure>
<p>include_flutter.groovy</p>
<figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line"><span class="keyword">def</span> scriptFile = getClass().protectionDomain.codeSource.location.toURI()</span><br><span class="line"><span class="keyword">def</span> flutterProjectRoot = <span class="keyword">new</span> File(scriptFile).parentFile.parentFile</span><br><span class="line">gradle.include <span class="string">':flutter'</span></span><br><span class="line">gradle.project(<span class="string">':flutter'</span>).projectDir = <span class="keyword">new</span> File(flutterProjectRoot, <span class="string">'.android/Flutter'</span>)</span><br><span class="line"><span class="keyword">def</span> plugins = <span class="keyword">new</span> Properties()</span><br><span class="line"><span class="keyword">def</span> pluginsFile = <span class="keyword">new</span> File(flutterProjectRoot, <span class="string">'.flutter-plugins'</span>)</span><br><span class="line"><span class="keyword">if</span> (pluginsFile.exists()) {</span><br><span class="line"> pluginsFile.withReader(<span class="string">'UTF-8'</span>) { reader -> plugins.load(reader) }</span><br><span class="line">}</span><br><span class="line">plugins.each { name, path -></span><br><span class="line"> <span class="keyword">def</span> pluginDirectory = flutterProjectRoot.toPath().resolve(path).resolve(<span class="string">'android'</span>).toFile()</span><br><span class="line"> gradle.include <span class="string">":$name"</span></span><br><span class="line"> gradle.project(<span class="string">":$name"</span>).projectDir = pluginDirectory</span><br><span class="line">}</span><br><span class="line">gradle.getGradle().projectsLoaded { g -></span><br><span class="line"> g.rootProject.beforeEvaluate { p -></span><br><span class="line"> _mainModuleName = binding.variables[<span class="string">'mainModuleName'</span>]</span><br><span class="line"> <span class="keyword">if</span> (_mainModuleName != <span class="literal">null</span> && !_mainModuleName.empty) {</span><br><span class="line"> p.ext.mainModuleName = _mainModuleName</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> g.rootProject.afterEvaluate { p -></span><br><span class="line"> p.subprojects { sp -></span><br><span class="line"> <span class="keyword">if</span> (sp.name != <span class="string">'flutter'</span>) {</span><br><span class="line"> sp.evaluationDependsOn(<span class="string">':flutter'</span>)</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="Android-Flutter-编译任务"><a href="#Android-Flutter-编译任务" class="headerlink" title="Android Flutter 编译任务"></a>Android Flutter 编译任务</h3><h5 id="Android-端Flutter编译过程"><a href="#Android-端Flutter编译过程" class="headerlink" title="Android 端Flutter编译过程"></a>Android 端Flutter编译过程</h5><ol>
<li><p>设置变异类型</p>
<figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line">project.android.buildTypes {</span><br><span class="line"> profile {</span><br><span class="line"> <span class="comment">// ... </span></span><br><span class="line"> }</span><br><span class="line"> dynamicProfile {</span><br><span class="line"> <span class="comment">// ... </span></span><br><span class="line"> }</span><br><span class="line"> dynamicRelease {</span><br><span class="line"> <span class="comment">// ... </span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
</li>
<li><p>设置Flutter Engine,如果本地有配置,则会使用本地的</p>
<figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line"><span class="keyword">if</span> (project.hasProperty(<span class="string">'localEngineOut'</span>)) {</span><br><span class="line"> <span class="comment">// 设置配置的Engine</span></span><br><span class="line">} <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">// 设置Flutter SDK中的Engine</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
</li>
<li><p>添加FlutterTask,并设置Flutter插件的依赖</p>
<figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line">project.extensions.create(<span class="string">"flutter"</span>, FlutterExtension)</span><br><span class="line">project.afterEvaluate <span class="variable language_">this</span>.&addFlutterTask</span><br><span class="line"><span class="comment">//...</span></span><br><span class="line">plugins.each { name, _ -></span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure></li>
</ol>
<h6 id="FlutterTask"><a href="#FlutterTask" class="headerlink" title="FlutterTask"></a>FlutterTask</h6><ol>
<li><p>设置编译参数</p>
<p>flutter 代码路径:</p>
<figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line">String target = project.flutter.target</span><br><span class="line"><span class="keyword">if</span> (target == <span class="literal">null</span>) {</span><br><span class="line"> target = <span class="string">'lib/main.dart'</span></span><br><span class="line">}</span><br><span class="line"><span class="keyword">if</span> (project.hasProperty(<span class="string">'target'</span>)) {</span><br><span class="line"> target = project.property(<span class="string">'target'</span>)</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>编译目标平台:</p>
<figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line">String targetPlatformValue = <span class="literal">null</span></span><br><span class="line"><span class="keyword">if</span> (project.hasProperty(<span class="string">'target-platform'</span>)) {</span><br><span class="line"> targetPlatformValue = project.property(<span class="string">'target-platform'</span>)</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>等等。</p>
</li>
<li><p>添加Flutter依赖以及FlutterTask</p>
<figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line"><span class="keyword">if</span> (project.android.hasProperty(<span class="string">"applicationVariants"</span>)) {</span><br><span class="line"> project.android.applicationVariants.all addFlutterDeps</span><br><span class="line">} <span class="keyword">else</span> {</span><br><span class="line"> project.android.libraryVariants.all addFlutterDeps</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>包含:vm_snapshot_data、vm_snapshot_instr、isolate_snapshot_data、isolate_snapshot_instr等,以及Flutter源代码等。Flutter 的编译过程是由源代码编译的,插件等提供的也是源代码依赖。</p>
</li>
<li><p>FlutterTask</p>
<p>Flutter 执行的便于指令:</p>
<figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line"><span class="type">void</span> buildBundle() {</span><br><span class="line"> <span class="keyword">if</span> (!sourceDir.isDirectory()) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> GradleException(<span class="string">"Invalid Flutter source directory: ${sourceDir}"</span>)</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> intermediateDir.mkdirs()</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (buildMode == <span class="string">"profile"</span> || buildMode == <span class="string">"release"</span>) {</span><br><span class="line"> project.exec {</span><br><span class="line"> executable flutterExecutable.absolutePath</span><br><span class="line"> workingDir sourceDir</span><br><span class="line"> <span class="keyword">if</span> (localEngine != <span class="literal">null</span>) {</span><br><span class="line"> args <span class="string">"--local-engine"</span>, localEngine</span><br><span class="line"> args <span class="string">"--local-engine-src-path"</span>, localEngineSrcPath</span><br><span class="line"> }</span><br><span class="line"> args <span class="string">"build"</span>, <span class="string">"aot"</span></span><br><span class="line"> args <span class="string">"--suppress-analytics"</span></span><br><span class="line"> args <span class="string">"--quiet"</span></span><br><span class="line"> args <span class="string">"--target"</span>, targetPath</span><br><span class="line"> args <span class="string">"--target-platform"</span>, <span class="string">"android-arm"</span></span><br><span class="line"> args <span class="string">"--output-dir"</span>, <span class="string">"${intermediateDir}"</span></span><br><span class="line"> <span class="keyword">if</span> (trackWidgetCreation) {</span><br><span class="line"> args <span class="string">"--track-widget-creation"</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (extraFrontEndOptions != <span class="literal">null</span>) {</span><br><span class="line"> args <span class="string">"--extra-front-end-options"</span>, <span class="string">"${extraFrontEndOptions}"</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (extraGenSnapshotOptions != <span class="literal">null</span>) {</span><br><span class="line"> args <span class="string">"--extra-gen-snapshot-options"</span>, <span class="string">"${extraGenSnapshotOptions}"</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (buildSharedLibrary) {</span><br><span class="line"> args <span class="string">"--build-shared-library"</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (targetPlatform != <span class="literal">null</span>) {</span><br><span class="line"> args <span class="string">"--target-platform"</span>, <span class="string">"${targetPlatform}"</span></span><br><span class="line"> }</span><br><span class="line"> args <span class="string">"--${buildMode}"</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> project.exec {</span><br><span class="line"> executable flutterExecutable.absolutePath</span><br><span class="line"> workingDir sourceDir</span><br><span class="line"> <span class="keyword">if</span> (localEngine != <span class="literal">null</span>) {</span><br><span class="line"> args <span class="string">"--local-engine"</span>, localEngine</span><br><span class="line"> args <span class="string">"--local-engine-src-path"</span>, localEngineSrcPath</span><br><span class="line"> }</span><br><span class="line"> args <span class="string">"build"</span>, <span class="string">"bundle"</span></span><br><span class="line"> args <span class="string">"--suppress-analytics"</span></span><br><span class="line"> args <span class="string">"--target"</span>, targetPath</span><br><span class="line"> <span class="keyword">if</span> (verbose) {</span><br><span class="line"> args <span class="string">"--verbose"</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (fileSystemRoots != <span class="literal">null</span>) {</span><br><span class="line"> <span class="keyword">for</span> (root <span class="keyword">in</span> fileSystemRoots) {</span><br><span class="line"> args <span class="string">"--filesystem-root"</span>, root</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (fileSystemScheme != <span class="literal">null</span>) {</span><br><span class="line"> args <span class="string">"--filesystem-scheme"</span>, fileSystemScheme</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (trackWidgetCreation) {</span><br><span class="line"> args <span class="string">"--track-widget-creation"</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (compilationTraceFilePath != <span class="literal">null</span>) {</span><br><span class="line"> args <span class="string">"--compilation-trace-file"</span>, compilationTraceFilePath</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (createPatch) {</span><br><span class="line"> args <span class="string">"--patch"</span></span><br><span class="line"> args <span class="string">"--build-number"</span>, project.android.defaultConfig.versionCode</span><br><span class="line"> <span class="keyword">if</span> (buildNumber != <span class="literal">null</span>) {</span><br><span class="line"> <span class="keyword">assert</span> buildNumber == project.android.defaultConfig.versionCode</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (baselineDir != <span class="literal">null</span>) {</span><br><span class="line"> args <span class="string">"--baseline-dir"</span>, baselineDir</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (extraFrontEndOptions != <span class="literal">null</span>) {</span><br><span class="line"> args <span class="string">"--extra-front-end-options"</span>, <span class="string">"${extraFrontEndOptions}"</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (extraGenSnapshotOptions != <span class="literal">null</span>) {</span><br><span class="line"> args <span class="string">"--extra-gen-snapshot-options"</span>, <span class="string">"${extraGenSnapshotOptions}"</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (targetPlatform != <span class="literal">null</span>) {</span><br><span class="line"> args <span class="string">"--target-platform"</span>, <span class="string">"${targetPlatform}"</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (buildMode == <span class="string">"release"</span> || buildMode == <span class="string">"profile"</span>) {</span><br><span class="line"> args <span class="string">"--precompiled"</span></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> args <span class="string">"--depfile"</span>, <span class="string">"${intermediateDir}/snapshot_blob.bin.d"</span></span><br><span class="line"> }</span><br><span class="line"> args <span class="string">"--asset-dir"</span>, <span class="string">"${intermediateDir}/flutter_assets"</span></span><br><span class="line"> <span class="keyword">if</span> (buildMode == <span class="string">"debug"</span>) {</span><br><span class="line"> args <span class="string">"--debug"</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (buildMode == <span class="string">"profile"</span> || buildMode == <span class="string">"dynamicProfile"</span>) {</span><br><span class="line"> args <span class="string">"--profile"</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (buildMode == <span class="string">"release"</span> || buildMode == <span class="string">"dynamicRelease"</span>) {</span><br><span class="line"> args <span class="string">"--release"</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (buildMode == <span class="string">"dynamicProfile"</span> || buildMode == <span class="string">"dynamicRelease"</span>) {</span><br><span class="line"> args <span class="string">"--dynamic"</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>flutterExecutable为flutter命令</p>
<p>当 buildType 为 debug 时:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">flutter build bundle --depfile <span class="variable">${intermediateDir}</span>/snapshot_blob.bin.d --debug</span></span><br></pre></td></tr></table></figure>
<p>当 buildType 为 release 时:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">flutter build aot</span></span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">flutter build bundle --precompiled --release</span></span><br></pre></td></tr></table></figure></li>
</ol>
<h5 id="Flutter-编译模型区别"><a href="#Flutter-编译模型区别" class="headerlink" title="Flutter 编译模型区别"></a>Flutter 编译模型区别</h5><p><a href="https://juejin.im/post/5d68fb1af265da03d063b69e">https://juejin.im/post/5d68fb1af265da03d063b69e</a></p>
<h3 id="二、-调试工具Dart-DevTools"><a href="#二、-调试工具Dart-DevTools" class="headerlink" title="二、 调试工具Dart DevTools"></a>二、 调试工具Dart DevTools</h3><ol>
<li>启动devtools</li>
</ol>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">pub global run devtools</span></span><br><span class="line">Serving DevTools at http://127.0.0.1:9100</span><br></pre></td></tr></table></figure>
<ol start="2">
<li> 在flutter lib同目录执行attach命令,等待App连接</li>
</ol>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">flutter attach</span></span><br><span class="line">Waiting for a connection from Flutter on MI 8...</span><br></pre></td></tr></table></figure>
<ol start="3">
<li>重新启动app,等待</li>
</ol>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">flutter attach</span></span><br><span class="line">Waiting for a connection from Flutter on MI 8...</span><br><span class="line">Done.</span><br><span class="line">Syncing files to device MI 8...</span><br><span class="line"> 3,832ms (!)</span><br><span class="line"></span><br><span class="line">🔥 To hot reload changes while running, press "r". To hot restart (and rebuild state), press "R".</span><br><span class="line">An Observatory debugger and profiler on MI 8 is available at: http://127.0.0.1:53469/Fv75Oo4wMEE=/</span><br><span class="line">For a more detailed help message, press "h". To detach, press "d"; to quit, press "q"</span><br></pre></td></tr></table></figure>
<ol start="4">
<li>打开chrome,<a href="http://127.0.0.1:9100/">http://127.0.0.1:9100</a> ,输入<code>flutter attach</code> 命令中的url <code>http://127.0.0.1:53469/Fv75Oo4wMEE=/</code></li>
</ol>
<img src="https://raw.githubusercontent.com/zauther/figurebed/blog/images/20200209200549.png" alt="image-20191024193054066" style="zoom:33%;" />
<ol start="5">
<li>通过Dart DevTools调试</li>
</ol>
<p><img src="https://raw.githubusercontent.com/zauther/figurebed/blog/images/20200209200719.png" alt="image-20191024193127816"></p>
<p>工具项:</p>
<ul>
<li>Flutter Inspector: 布局调试工具</li>
<li>Timeline : </li>
<li>Memory : 内存使用情况</li>
<li>Performance :</li>
<li>Debugger: 断点调试工具</li>
<li>Logging : Log输出</li>
<li>Hot Reload</li>
<li>Hot Restart</li>
</ul>
<h6 id="Flutter-Inspector:Flutter-布局调试工具"><a href="#Flutter-Inspector:Flutter-布局调试工具" class="headerlink" title="Flutter Inspector:Flutter 布局调试工具"></a>Flutter Inspector:Flutter 布局调试工具</h6><p>Performance Overlay :</p>
<img src="/Users/zauther/Library/Application Support/typora-user-images/image-20191024200900434.png" alt="image-20191024200900434" style="zoom:33%;" />
<p>Paint Baselines:</p>
<img src="/Users/zauther/Library/Application Support/typora-user-images/image-20191024201205498.png" alt="image-20191024201205498" style="zoom:33%;" />
<p>Debug Paint:</p>
<img src="/Users/zauther/Library/Application Support/typora-user-images/image-20191024193810095.png" alt="image-20191024193810095" style="zoom: 33%;" />
<p>当项目为Flutter工程时,可以直接通过Android Studio进行调试,当以Module的形式引入时,目前无法直接通过Android Studio进行调试,可采用Dart DevTools在Chrome中调试。</p>
<p></p>
<h3 id="三、Flutter-接入实践"><a href="#三、Flutter-接入实践" class="headerlink" title="三、Flutter 接入实践"></a>三、Flutter 接入实践</h3><h3 id="接入现有ReactNative工程"><a href="#接入现有ReactNative工程" class="headerlink" title="接入现有ReactNative工程"></a>接入现有ReactNative工程</h3><h4 id="1-在Android测"><a href="#1-在Android测" class="headerlink" title="1. 在Android测"></a>1. 在Android测</h4><ol>
<li>引入Flutter Module</li>
</ol>
<figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line">setBinding(<span class="keyword">new</span> Binding([<span class="attr">gradle:</span> <span class="variable language_">this</span>]))</span><br><span class="line">evaluate(<span class="keyword">new</span> File(rootProject.projectDir, <span class="string">'./fluttermodule/android/include_flutter.groovy'</span>))</span><br></pre></td></tr></table></figure>
<ol start="2">
<li>在include_flutter.groovy指定自己的Flutter模块,因为.android目录是自己生成的,内容会被覆盖,可自定义模块</li>
</ol>
<figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line">gradle.include <span class="string">':flutter'</span></span><br><span class="line">gradle.project(<span class="string">':flutter'</span>).projectDir = <span class="keyword">new</span> File(flutterProjectRoot, <span class="string">'android/Flutter'</span>)</span><br></pre></td></tr></table></figure>
<ol start="3">
<li>定义FlutterActivity,并在AndroidManifest.xml中注册,此处集成FlutterBoost的BoostFlutterActivity,也可以使用Flutter原生的FlutterActivity。</li>
</ol>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">FlutterPageActivity</span> <span class="keyword">extends</span> <span class="title class_">BoostFlutterActivity</span> {</span><br><span class="line"> <span class="keyword">private</span> String url;</span><br><span class="line"> <span class="keyword">private</span> HashMap params;</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onCreate</span><span class="params">(Bundle saveInstanceBundle)</span> {</span><br><span class="line"> <span class="comment">// onCreate</span></span><br><span class="line"> }</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onRegisterPlugins</span><span class="params">(PluginRegistry registry)</span> {</span><br><span class="line"> <span class="comment">// register flutter plugins</span></span><br><span class="line"> }</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> String <span class="title function_">getContainerName</span><span class="params">()</span> {</span><br><span class="line"> <span class="type">return</span> <span class="variable">url</span> <span class="operator">=</span>= <span class="literal">null</span> ? <span class="string">""</span> : url;</span><br><span class="line"> }</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> Map <span class="title function_">getContainerParams</span><span class="params">()</span> {</span><br><span class="line"> <span class="comment">// params of the page</span></span><br><span class="line"> <span class="type">return</span> <span class="variable">params</span> <span class="operator">=</span>= <span class="literal">null</span> ? <span class="keyword">new</span> <span class="title class_">HashMap</span>() : params;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MainActivity</span> <span class="keyword">extends</span> <span class="title class_">FlutterActivity</span> {</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">onCreate</span><span class="params">(Bundle savedInstanceState)</span> {</span><br><span class="line"> <span class="built_in">super</span>.onCreate(savedInstanceState);</span><br><span class="line"> GeneratedPluginRegistrant.registerWith(<span class="built_in">this</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>FlutterActivity,用于承接Flutter界面</p>
<ol start="4">
<li>在Application中初始化Flutter框架</li>
</ol>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">FlutterMain.startInitialization(context);</span><br></pre></td></tr></table></figure>
<p>如果使用FlutterBoost,在初始化Flutter框架后,初始化FlutterBoost插件:</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">FlutterBoostPlugin.init(platform);</span><br></pre></td></tr></table></figure>
<h4 id="2-在ReactNative测"><a href="#2-在ReactNative测" class="headerlink" title="2. 在ReactNative测"></a>2. 在ReactNative测</h4><ol>
<li>自定义方法</li>
</ol>
<figure class="highlight js"><table><tr><td class="code"><pre><span class="line"><span class="title class_">FlutterSupport</span>.<span class="property">openFlutterPage</span> = <span class="keyword">function</span> (<span class="params">url, params</span>){</span><br><span class="line"> <span class="title class_">NativeModules</span>.<span class="property">RNFlutterSupport</span>.<span class="title function_">openFlutterPage</span>(url, params)</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<ol start="2">
<li>新建ReactNativeModules,并注册到ReactNativeHost中</li>
</ol>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">RNFlutterSupportModule</span> <span class="keyword">extends</span> <span class="title class_">ReactContextBaseJavaModule</span>{</span><br><span class="line"> <span class="meta">@ReactMethod</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">openFlutterPage</span><span class="params">(String url, ReadableMap params)</span> {</span><br><span class="line"> <span class="comment">// RN侧调用,RNToFlutterManager根据url来判断跳转到哪个Flutter页面</span></span><br><span class="line"> RNToFlutterManager.openFlutterPage(reactContext, url, params == <span class="literal">null</span> ? <span class="keyword">new</span> <span class="title class_">HashMap</span>() : params.toHashMap(), <span class="number">0</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// RN侧调用Flutter方法</span></span><br><span class="line"> <span class="meta">@ReactMethod</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">invokeCallback</span><span class="params">(String callbackId, ReadableMap data)</span> {</span><br><span class="line"> <span class="type">ReactFlutterEventEmitterCallbackEvent</span> <span class="variable">callbackEvent</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ReactFlutterEventEmitterCallbackEvent</span>();</span><br><span class="line"> callbackEvent.callBackId = callbackId;</span><br><span class="line"> callbackEvent.data = data;</span><br><span class="line"> mEmitter.onReactCallbackEvent(callbackEvent);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 用于Flutter侧调用RN的方法</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">methodCallReactNative</span><span class="params">(String method, Object arguments, <span class="keyword">final</span> Callback callback)</span> {</span><br><span class="line"> mEmitter.sendEvent(reactContext, method, arguments, callback == <span class="literal">null</span> ? <span class="literal">null</span> : <span class="keyword">new</span> <span class="title class_">ReactFlutterEventEmitterCallbackHandler</span>() {</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">handler</span><span class="params">(ReadableMap data)</span> {</span><br><span class="line"> callback.invoke(data.toHashMap());</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"> }</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> String <span class="title function_">getName</span><span class="params">()</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"RNFlutterSupport"</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">RNFlutterSupportPackage</span> <span class="keyword">implements</span> <span class="title class_">ReactPackage</span> {</span><br><span class="line"> <span class="keyword">public</span> RNFlutterSupportModule mRNFlutterSupportModule;</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> List<NativeModule> <span class="title function_">createNativeModules</span><span class="params">(ReactApplicationContext reactContext)</span> {</span><br><span class="line"> mRNFlutterSupportModule = <span class="keyword">new</span> <span class="title class_">RNFlutterSupportModule</span>(reactContext);</span><br><span class="line"> <span class="keyword">return</span> Arrays.<NativeModule>asList(mRNFlutterSupportModule);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// Deprecated from RN 0.47</span></span><br><span class="line"> <span class="keyword">public</span> List<Class<? <span class="keyword">extends</span> <span class="title class_">JavaScriptModule</span>>> createJSModules() {</span><br><span class="line"> <span class="keyword">return</span> Collections.emptyList();</span><br><span class="line"> }</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> List<ViewManager> <span class="title function_">createViewManagers</span><span class="params">(ReactApplicationContext reactContext)</span> {</span><br><span class="line"> <span class="keyword">return</span> Collections.emptyList();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>其中:</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">openFlutterPage</span><span class="params">(Context context, String url, <span class="keyword">final</span> HashMap params, <span class="type">int</span> requestCode)</span> {</span><br><span class="line"> <span class="type">Intent</span> <span class="variable">intent</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Intent</span>(context, FlutterPageActivity.class);</span><br><span class="line"> intent.putExtra(<span class="string">"url"</span>, url);</span><br><span class="line"> intent.putExtra(<span class="string">"params"</span>, params);</span><br><span class="line"> <span class="keyword">if</span> (params != <span class="literal">null</span> && params.containsKey(<span class="string">"flags"</span>)) {</span><br><span class="line"> <span class="type">String</span> <span class="variable">flags</span> <span class="operator">=</span> (String) params.get(<span class="string">"flags"</span>);</span><br><span class="line"> <span class="keyword">if</span> (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && <span class="string">"CLEAR_TASK"</span>.equals(flags)) {</span><br><span class="line"> intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);</span><br><span class="line"> }</span><br><span class="line"> context.startActivity(intent);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="FlutterBoost-使用"><a href="#FlutterBoost-使用" class="headerlink" title="FlutterBoost 使用"></a>FlutterBoost 使用</h3><p>在pubspec.yaml添加插件:</p>
<figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="attr">flutter_boost:</span> <span class="string">^0.0.415</span></span><br></pre></td></tr></table></figure>
<p>在Application中:</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">FlutterBoostPlugin.init(<span class="keyword">new</span> <span class="title class_">IFlutterPlatform</span>() {</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> Application <span class="title function_">getApplication</span><span class="params">()</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> Activity <span class="title function_">getMainActivity</span><span class="params">()</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">isDebug</span><span class="params">()</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">startActivity</span><span class="params">(Context context, String url, <span class="type">int</span> requestCode)</span> {</span><br><span class="line"> <span class="comment">// flutter 跳转原生</span></span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> Map <span class="title function_">getSettings</span><span class="params">()</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line"> }</span><br><span class="line">});</span><br></pre></td></tr></table></figure>
<p>在Flutter main.dart中注册页面并初始化FlutterBoost:</p>
<figure class="highlight dart"><table><tr><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">_MyAPPState</span> <span class="keyword">extends</span> <span class="title">State</span><<span class="title">MyApp</span>> </span>{</span><br><span class="line"> <span class="meta">@override</span></span><br><span class="line"> <span class="keyword">void</span> initState() {</span><br><span class="line"> FlutterBoost.singleton.registerPageBuilders({</span><br><span class="line"> <span class="string">'teemo.home'</span>: (pageName, params, _) => HomePageWidget(params),</span><br><span class="line"> <span class="string">'teemo.settings'</span>: (pageName, params, _) => SettingPageWidget(params),</span><br><span class="line"> <span class="string">'teemo.changeenv'</span>: (pageName, params, _) => ChangeEnvPageWidget(params),</span><br><span class="line"> <span class="string">'teemo.cabinet.errorreport'</span>: (pageName, params, _) =></span><br><span class="line"> ErrorReportPage(params),</span><br><span class="line"> <span class="string">'teemo.order.orderdetail'</span>: (pageName, params, _) =></span><br><span class="line"> OrderDetailPage(params),</span><br><span class="line"> });</span><br><span class="line"> FlutterBoost.handleOnStartPage();</span><br><span class="line"> <span class="keyword">super</span>.initState();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@override</span></span><br><span class="line"> Widget build(BuildContext context) {</span><br><span class="line"> <span class="keyword">return</span> MaterialApp(</span><br><span class="line"> title: <span class="string">'Teemo'</span>,</span><br><span class="line"> builder: FlutterBoost.init(),</span><br><span class="line"> home: <span class="keyword">new</span> Container(),</span><br><span class="line"> localizationsDelegates: [</span><br><span class="line"> RefreshLocalizations.delegate,</span><br><span class="line"> GlobalMaterialLocalizations.delegate,</span><br><span class="line"> GlobalWidgetsLocalizations.delegate,</span><br><span class="line"> <span class="keyword">const</span> FallbackCupertinoLocalisationsDelegate(),</span><br><span class="line"> ],</span><br><span class="line"> supportedLocales: [</span><br><span class="line"> <span class="keyword">const</span> Locale(<span class="string">'zh'</span>, <span class="string">'CH'</span>),</span><br><span class="line"> <span class="keyword">const</span> Locale(<span class="string">'en'</span>, <span class="string">'US'</span>),</span><br><span class="line"> ],</span><br><span class="line"> );</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>Flutter 中跳转页面:</p>
<figure class="highlight dart"><table><tr><td class="code"><pre><span class="line">FlutterBoost.singleton.openPage(<span class="string">'teemo.settings'</span>,</span><br><span class="line"> {<span class="string">'canChangeRole'</span>: canChangeRole ? <span class="string">"1"</span> : <span class="string">"0"</span>},</span><br><span class="line"> animated: <span class="keyword">true</span>);</span><br></pre></td></tr></table></figure>
<p>FlutterBoost flutter测常用方法:</p>
<figure class="highlight dart"><table><tr><td class="code"><pre><span class="line">FlutterBoost.singleton.openPage(<span class="built_in">String</span> url, <span class="built_in">Map</span> params,</span><br><span class="line"> {<span class="built_in">bool</span> animated, PageResultHandler resultHandler});</span><br><span class="line">FlutterBoost.singleton.closePage(<span class="built_in">String</span> url, <span class="built_in">String</span> pageId, <span class="built_in">Map</span> params,</span><br><span class="line"> {<span class="built_in">bool</span> animated});</span><br><span class="line">FlutterBoost.singleton.closeCurPage(<span class="built_in">Map</span> params);</span><br><span class="line">FlutterBoost.handleOnStartPage();</span><br></pre></td></tr></table></figure>
]]></content>
<categories>
<category>Flutter</category>
</categories>
<tags>
<tag>Flutter</tag>
<tag>ReactNative</tag>
</tags>
</entry>
<entry>
<title>Gradle 用法</title>
<url>/2021/11/21/Gradle%20%E7%94%A8%E6%B3%95/</url>
<content><![CDATA[<p>主要包含:</p>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line">settings.gradle</span><br><span class="line">build.gradle</span><br><span class="line">app/build.gradle</span><br></pre></td></tr></table></figure>
<p>以及gradle wrapper下的gradle jar包和配置文件</p>
<span id="more"></span>
<h4 id="Gradle-文件执行顺序"><a href="#Gradle-文件执行顺序" class="headerlink" title="Gradle 文件执行顺序"></a>Gradle 文件执行顺序</h4><figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line"><span class="comment">//settings.gradle</span></span><br><span class="line">println(<span class="string">"setting 开始配置"</span>)</span><br><span class="line">include <span class="string">':app'</span></span><br><span class="line">rootProject.name=<span class="string">'Hello'</span></span><br><span class="line">println(<span class="string">"setting 配置完成"</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//project build.gradle</span></span><br><span class="line">println(<span class="string">"根build.gradle 开始配置"</span>)</span><br><span class="line">buildscript {</span><br><span class="line"> repositories {</span><br><span class="line"> }</span><br><span class="line"> dependencies {</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line">println(<span class="string">"根build.gradle 配置完成"</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//app build.gradle</span></span><br><span class="line">println(<span class="string">"app build.gradle 开始配置"</span>)</span><br><span class="line"></span><br><span class="line">project.afterEvaluate {</span><br><span class="line"> println <span class="string">"所有模块都已配置完成"</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">android {</span><br><span class="line"> defaultConfig {</span><br><span class="line"> }</span><br><span class="line"> buildTypes {</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">dependencies {</span><br><span class="line">}</span><br><span class="line">println(<span class="string">"app build.gradle 配置完成"</span>)</span><br></pre></td></tr></table></figure>
<p>三个文件中:<br>settings.gradle 先执行<br>build.gradle 第二执行<br>app/build.gradle 第三执行,如果注册了 project.afterEvaluate ,则后执行<br>在不同文件中注册project.afterEvaluate,对于不同的project</p>
<figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line">setting 开始配置</span><br><span class="line">setting 配置完成</span><br><span class="line"></span><br><span class="line">> Configure <span class="attr">project :</span></span><br><span class="line">根build.gradle 开始配置</span><br><span class="line">根build.gradle 配置完成</span><br><span class="line">build.gradle 所有模块都已配置完成</span><br><span class="line"></span><br><span class="line">> Configure <span class="attr">project :</span>app</span><br><span class="line">app build.gradle 开始配置</span><br><span class="line">app build.gradle 配置完成</span><br><span class="line">app build.gradle 所有模块都已配置完成</span><br></pre></td></tr></table></figure>
<p>在settings.gradle中添加</p>
<figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line">gradle.addBuildListener(<span class="keyword">new</span> BuildListener() {</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="type">void</span> beforeSettings(Settings settings) {</span><br><span class="line"> <span class="variable language_">super</span>.beforeSettings(settings)</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="type">void</span> settingsEvaluated(Settings settings) {</span><br><span class="line"> println(<span class="string">"settingsEvaluated------------"</span>)</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="type">void</span> projectsLoaded(Gradle gradle) {</span><br><span class="line"> println(<span class="string">"projectsLoaded------------"</span>)</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="type">void</span> projectsEvaluated(Gradle gradle) {</span><br><span class="line"> println(<span class="string">"projectsEvaluated------------"</span>)</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="type">void</span> buildFinished(BuildResult result) {</span><br><span class="line"> println(<span class="string">"buildFinished------------"</span>)</span><br><span class="line"> }</span><br><span class="line">})</span><br></pre></td></tr></table></figure>
<p>输出</p>
<figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line">setting 开始配置</span><br><span class="line">setting 配置完成</span><br><span class="line">settingsEvaluated------------</span><br><span class="line">projectsLoaded------------</span><br><span class="line"></span><br><span class="line">> Configure <span class="attr">project :</span></span><br><span class="line">根build.gradle 开始配置</span><br><span class="line">根build.gradle 配置完成</span><br><span class="line">build.gradle 所有模块都已配置完成</span><br><span class="line"></span><br><span class="line">> Configure <span class="attr">project :</span>app</span><br><span class="line">app build.gradle 开始配置</span><br><span class="line">app build.gradle 配置完成</span><br><span class="line">app build.gradle 所有模块都已配置完成</span><br><span class="line">projectsEvaluated------------</span><br><span class="line">buildFinished------------</span><br></pre></td></tr></table></figure>
<p>如果是在build.gradle中添加则输出</p>
<figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line">setting 开始配置</span><br><span class="line">setting 配置完成</span><br><span class="line"></span><br><span class="line">> Configure <span class="attr">project :</span></span><br><span class="line">根build.gradle 开始配置</span><br><span class="line">根build.gradle 配置完成</span><br><span class="line">build.gradle 所有模块都已配置完成</span><br><span class="line"></span><br><span class="line">> Configure <span class="attr">project :</span>app</span><br><span class="line">app build.gradle 开始配置</span><br><span class="line">app build.gradle 配置完成</span><br><span class="line">app build.gradle 所有模块都已配置完成</span><br><span class="line">projectsEvaluated------------</span><br><span class="line">buildFinished------------</span><br></pre></td></tr></table></figure>
<p>可以看到settingsEvaluated、projectsLoaded相关的没有打印,因为这个时候settingsEvaluated和projectsLoaded已经执行过了。<br></p>
<h4 id="Gradle-Task"><a href="#Gradle-Task" class="headerlink" title="Gradle Task"></a>Gradle Task</h4><p>在build.gradle文件中:</p>
<figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line">task hello() {</span><br><span class="line"> println <span class="string">"hello world"</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">//将给定的闭包 添加到此task操作链表的开头</span></span><br><span class="line"> doFirst {</span><br><span class="line"> println <span class="string">"hello task doFirst"</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> doLast {</span><br><span class="line"> println <span class="string">"hello task doLast"</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>settings.gradle是项目配置文件,无法添加task。</p>
<figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line">setting 开始配置</span><br><span class="line">setting 配置完成</span><br><span class="line"></span><br><span class="line">> Configure <span class="attr">project :</span></span><br><span class="line">根build.gradle 开始配置</span><br><span class="line">根build.gradle 配置完成</span><br><span class="line">hello world</span><br><span class="line">build.gradle 所有模块都已配置完成</span><br><span class="line"></span><br><span class="line">> Configure <span class="attr">project :</span>app</span><br><span class="line">app build.gradle 开始配置</span><br><span class="line">app build.gradle 配置完成</span><br><span class="line">app build.gradle 所有模块都已配置完成</span><br><span class="line"></span><br><span class="line">> <span class="attr">Task :</span>hello</span><br><span class="line">hello task doFirst</span><br><span class="line">hello task doLast</span><br></pre></td></tr></table></figure>
<p>可以看到,会先执行配置,然后才会执行task。<br>其中ext是内置变量</p>
<figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line">ext.a=<span class="string">"1222"</span></span><br><span class="line"></span><br><span class="line">task hello() {</span><br><span class="line"> println <span class="string">"hello world"</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">//将给定的闭包 添加到此task操作链表的开头</span></span><br><span class="line"> doFirst {</span><br><span class="line"> println <span class="string">"hello task doFirst:$a"</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> doLast {</span><br><span class="line"> println <span class="string">"hello task doLast"</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line">> <span class="attr">Task :</span>hello</span><br><span class="line">hello task <span class="attr">doFirst:</span><span class="number">1222</span></span><br><span class="line">hello task doLast</span><br></pre></td></tr></table></figure>
<h4 id="Build监听"><a href="#Build监听" class="headerlink" title="Build监听"></a>Build监听</h4><p>在settings.gradle中配置</p>
<figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line">gradle.addBuildListener(<span class="keyword">new</span> BuildListener() {</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="type">void</span> beforeSettings(Settings settings) {</span><br><span class="line"> <span class="variable language_">super</span>.beforeSettings(settings)</span><br><span class="line"> println(<span class="string">"beforeSettings------------"</span>)</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="type">void</span> settingsEvaluated(Settings settings) {</span><br><span class="line"> println(<span class="string">"settingsEvaluated------------"</span>)</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="type">void</span> projectsLoaded(Gradle gradle) {</span><br><span class="line"> println(<span class="string">"projectsLoaded------------"</span>)</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="type">void</span> projectsEvaluated(Gradle gradle) {</span><br><span class="line"> println(<span class="string">"projectsEvaluated------------"</span>)</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="type">void</span> buildFinished(BuildResult result) {</span><br><span class="line"> println(<span class="string">"buildFinished------------"</span>)</span><br><span class="line"> }</span><br><span class="line">})</span><br></pre></td></tr></table></figure>
<p>输出</p>
<figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line">setting 开始配置</span><br><span class="line">setting 配置完成</span><br><span class="line">settingsEvaluated------------</span><br><span class="line">projectsLoaded------------</span><br><span class="line"></span><br><span class="line">> Configure <span class="attr">project :</span></span><br><span class="line">根build.gradle 开始配置</span><br><span class="line">根build.gradle 配置完成</span><br><span class="line">hello world</span><br><span class="line">build.gradle 所有模块都已配置完成</span><br><span class="line"></span><br><span class="line">> Configure <span class="attr">project :</span>app</span><br><span class="line">app build.gradle 开始配置</span><br><span class="line">app build.gradle 配置完成</span><br><span class="line">app build.gradle 所有模块都已配置完成</span><br><span class="line">projectsEvaluated------------</span><br><span class="line">buildFinished------------</span><br></pre></td></tr></table></figure>
<p>当执行assemble时</p>
<figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line">setting 开始配置</span><br><span class="line">setting 配置完成</span><br><span class="line">settingsEvaluated------------</span><br><span class="line">projectsLoaded------------</span><br><span class="line"></span><br><span class="line">> Configure <span class="attr">project :</span></span><br><span class="line">根build.gradle 开始配置</span><br><span class="line">根build.gradle 配置完成</span><br><span class="line">hello world</span><br><span class="line">build.gradle 所有模块都已配置完成</span><br><span class="line"></span><br><span class="line">> Configure <span class="attr">project :</span>app</span><br><span class="line">app build.gradle 开始配置</span><br><span class="line">app build.gradle 配置完成</span><br><span class="line">app build.gradle 所有模块都已配置完成</span><br><span class="line">projectsEvaluated------------</span><br><span class="line"></span><br><span class="line">> <span class="attr">Task :</span><span class="attr">app:</span>preBuild UP-TO-DATE</span><br><span class="line">> <span class="attr">Task :</span><span class="attr">app:</span>preDebugBuild UP-TO-DATE</span><br><span class="line">...</span><br><span class="line">buildFinished------------</span><br></pre></td></tr></table></figure>
<p>可以看到,先执行Evaluated settings,然后是Loaded projects,每个项目的配置设置完后,projectsEvaluated。之后执行各种Task。执行完最后完成buildFinished。<br></p>
<h4 id="Task执行监听"><a href="#Task执行监听" class="headerlink" title="Task执行监听"></a>Task执行监听</h4><figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line">gradle.addListener(<span class="keyword">new</span> TaskExecutionListener() {</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="type">void</span> beforeExecute(Task task) {</span><br><span class="line"> println <span class="string">"打印beforeExecute ${task} =="</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="type">void</span> afterExecute(Task task, TaskState taskState) {</span><br><span class="line"> println <span class="string">"打印afterExecute ${task.getPath()} --- ${taskState} =="</span></span><br><span class="line"> }</span><br><span class="line">})</span><br></pre></td></tr></table></figure>
<p>输出:</p>
<figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line">setting 开始配置</span><br><span class="line">setting 配置完成</span><br><span class="line"></span><br><span class="line">> Configure <span class="attr">project :</span></span><br><span class="line">根build.gradle 开始配置</span><br><span class="line">根build.gradle 配置完成</span><br><span class="line">hello world</span><br><span class="line">build.gradle 所有模块都已配置完成</span><br><span class="line"></span><br><span class="line">> Configure <span class="attr">project :</span>app</span><br><span class="line">app build.gradle 开始配置</span><br><span class="line">app build.gradle 配置完成</span><br><span class="line">app build.gradle 所有模块都已配置完成</span><br><span class="line"></span><br><span class="line">> <span class="attr">Task :</span><span class="attr">app:</span>preBuild UP-TO-DATE</span><br><span class="line">打印beforeExecute task <span class="string">':app:preBuild'</span> ==</span><br><span class="line">打印<span class="attr">afterExecute :</span><span class="attr">app:</span>preBuild --- org.gradle.api.internal.tasks.TaskStateInternal@<span class="number">6</span>bbf2d19 ==</span><br><span class="line"></span><br><span class="line">> <span class="attr">Task :</span><span class="attr">app:</span>preDebugBuild UP-TO-DATE</span><br><span class="line">打印beforeExecute task <span class="string">':app:preDebugBuild'</span> ==</span><br><span class="line">打印<span class="attr">afterExecute :</span><span class="attr">app:</span>preDebugBuild --- org.gradle.api.internal.tasks.TaskStateInternal@<span class="number">62</span>fecb05 ==</span><br><span class="line">...</span><br></pre></td></tr></table></figure>
<p>会在task执行前后打印日志<br></p>
<h4 id="Gradle-插件"><a href="#Gradle-插件" class="headerlink" title="Gradle 插件"></a>Gradle 插件</h4><figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line">println(<span class="string">"before apply plugin"</span>)</span><br><span class="line">apply <span class="attr">plugin:</span> MyPlugin</span><br><span class="line">println(<span class="string">"after apply plugin"</span>)</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">MyPlugin</span> <span class="keyword">implements</span> <span class="title class_">Plugin</span><Project>{</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="type">void</span> apply(Project project) {</span><br><span class="line"> println <span class="string">"apply MyPlugin: ${project.name}"</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line">setting 开始配置</span><br><span class="line">setting 配置完成</span><br><span class="line"></span><br><span class="line">> Configure <span class="attr">project :</span></span><br><span class="line">根build.gradle 开始配置</span><br><span class="line">根build.gradle 配置完成</span><br><span class="line">hello world</span><br><span class="line">build.gradle 所有模块都已配置完成</span><br><span class="line"></span><br><span class="line">> Configure <span class="attr">project :</span>app</span><br><span class="line">app build.gradle 开始配置</span><br><span class="line">app build.gradle 配置完成</span><br><span class="line">before apply plugin</span><br><span class="line">apply <span class="attr">MyPlugin:</span> app</span><br><span class="line">after apply plugin</span><br><span class="line">app build.gradle 所有模块都已配置完成</span><br></pre></td></tr></table></figure>
<p>可以看到插件走的是配置。在配置时,会执行插件的apply。</p>
<figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line">println(<span class="string">"before apply plugin"</span>)</span><br><span class="line">apply <span class="attr">plugin:</span> MyPlugin</span><br><span class="line">println(<span class="string">"after apply plugin"</span>)</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">MyPlugin</span> <span class="keyword">implements</span> <span class="title class_">Plugin</span><Project>{</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="type">void</span> apply(Project project) {</span><br><span class="line"> println <span class="string">"apply MyPlugin: ${project.name}"</span></span><br><span class="line"> project.extensions.add(<span class="string">"testKey"</span>,<span class="string">"helloWork"</span>)</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line">println(<span class="string">"$testKey"</span>)</span><br></pre></td></tr></table></figure>
<p>通过 <code>apply plugin: MyPlugin</code> 后,将<code>testKey</code> 设置到<code>project.extensions</code> 中,后面直接使用。<br></p>
<h4 id="Gradle-Project"><a href="#Gradle-Project" class="headerlink" title="Gradle Project"></a>Gradle Project</h4><p>gradle project常用属性:</p>
<figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line">project.afterEvaluate{</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">project.plugins.hasPlugin(<span class="string">"com.android.library"</span>)</span><br><span class="line"></span><br><span class="line">project.configurations</span><br><span class="line"></span><br><span class="line">project.gradle.addListener()</span><br></pre></td></tr></table></figure>
<p>通过project中的字段来设置一些东西。<br></p>
<h4 id="Gradle-依赖"><a href="#Gradle-依赖" class="headerlink" title="Gradle 依赖"></a>Gradle 依赖</h4><figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line">project.gradle.addListener(<span class="keyword">new</span> DependencyResolutionListener(){</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="type">void</span> beforeResolve(ResolvableDependencies resolvableDependencies) {</span><br><span class="line"> <span class="comment">// 此处可以改变或替换依赖</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="type">void</span> afterResolve(ResolvableDependencies resolvableDependencies) {</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line">})</span><br></pre></td></tr></table></figure>
<h4 id="Gradle-插件添加任务"><a href="#Gradle-插件添加任务" class="headerlink" title="Gradle 插件添加任务"></a>Gradle 插件添加任务</h4><figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">MyTaskPlugin</span> <span class="keyword">implements</span> <span class="title class_">Plugin</span><Project>{</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="type">void</span> apply(Project project) {</span><br><span class="line"> project.task(...)</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">MyProjectTask</span> <span class="keyword">extends</span> <span class="title class_">DefaultTask</span>{</span><br><span class="line"> <span class="meta">@Input</span></span><br><span class="line"> String xxx</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Input</span></span><br><span class="line"> String yyy</span><br><span class="line"></span><br><span class="line"> <span class="meta">@TaskAction</span></span><br><span class="line"> <span class="type">void</span> doPackage() {</span><br><span class="line"> <span class="comment">// 执行任务</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h4 id="打印task耗时Demo"><a href="#打印task耗时Demo" class="headerlink" title="打印task耗时Demo"></a>打印task耗时Demo</h4><figure class="highlight groovy"><table><tr><td class="code"><pre><span class="line">apply <span class="attr">plugin:</span> MyPlugin</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">MyPlugin</span> <span class="keyword">implements</span> <span class="title class_">Plugin</span><Project>{</span><br><span class="line"> <span class="keyword">private</span> Project mProject;</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="type">void</span> apply(Project project) {</span><br><span class="line"> mProject = project;</span><br><span class="line"> <span class="comment">//注册监听,以统计任务的耗时</span></span><br><span class="line"> project.gradle.addListener(<span class="keyword">new</span> BuildTimeListener())</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">BuildTimeListener</span> <span class="keyword">implements</span> <span class="title class_">TaskExecutionListener</span>, BuildListener {</span><br><span class="line"></span><br><span class="line"> <span class="comment">//用来记录 task 的执行时长信息</span></span><br><span class="line"> Map<String, TaskTimeInfo> taskTimeMap = <span class="keyword">new</span> HashMap<>()</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="type">void</span> buildStarted(Gradle gradle) {</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="type">void</span> settingsEvaluated(Settings settings) {</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="type">void</span> projectsLoaded(Gradle gradle) {</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="type">void</span> projectsEvaluated(Gradle gradle) {</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="type">void</span> buildFinished(BuildResult buildResult) {</span><br><span class="line"> println <span class="string">"-----------------GouAPM----------------------"</span></span><br><span class="line"> println <span class="string">"---------------------------------------"</span></span><br><span class="line"> println <span class="string">"build finished, now println all task execution time:"</span></span><br><span class="line"> taskTimeMap.each{ k, v -> println <span class="string">"${k}:[${v.total}ms]"</span> }</span><br><span class="line"> println <span class="string">"---------------------------------------"</span></span><br><span class="line"> println <span class="string">"---------------------------------------"</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="type">void</span> beforeExecute(Task task) {</span><br><span class="line"> <span class="comment">//task开始执行之前搜集task的信息</span></span><br><span class="line"> TaskTimeInfo timeInfo = <span class="keyword">new</span> TaskTimeInfo()</span><br><span class="line"> timeInfo.start = System.currentTimeMillis()</span><br><span class="line"> timeInfo.path = task.getPath()</span><br><span class="line"> taskTimeMap.put(task.getPath(), timeInfo)</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="type">void</span> afterExecute(Task task, TaskState taskState) {</span><br><span class="line"> <span class="comment">//task执行完之后,记录结束时的时间</span></span><br><span class="line"> TaskTimeInfo timeInfo = taskTimeMap.get(task.getPath())</span><br><span class="line"> timeInfo.end = System.currentTimeMillis()</span><br><span class="line"> <span class="comment">//计算该 task 的执行时长</span></span><br><span class="line"> timeInfo.total = timeInfo.end - timeInfo.start</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">class</span> <span class="title class_">TaskTimeInfo</span> {</span><br><span class="line"> <span class="comment">//task执行总时长</span></span><br><span class="line"> <span class="type">long</span> total</span><br><span class="line"> String path</span><br><span class="line"> <span class="type">long</span> start</span><br><span class="line"> <span class="type">long</span> end</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
]]></content>
<categories>
<category>Android</category>
</categories>
<tags>
<tag>Android</tag>
<tag>Gradle</tag>
</tags>
</entry>
<entry>
<title>Java注解</title>
<url>/2016/03/27/Java%E6%B3%A8%E8%A7%A3/</url>
<content><![CDATA[<h4 id="java注解"><a href="#java注解" class="headerlink" title="java注解"></a>java注解</h4><p>annotation并不直接影响代码,不会改变程序的变异方式,java编译器对于包含注解和不包含注解的代码会生成相同的虚拟机指令</p>
<h4 id="注解使用范围"><a href="#注解使用范围" class="headerlink" title="注解使用范围"></a>注解使用范围</h4><ul>
<li>类</li>
<li>成员方法</li>
<li>成员变量</li>
</ul>
<h4 id="注解使用方法"><a href="#注解使用方法" class="headerlink" title="注解使用方法"></a>注解使用方法</h4><h5 id="基本定义"><a href="#基本定义" class="headerlink" title="基本定义"></a>基本定义</h5><ul>
<li>注解定义0(基本定义)</li>
</ul>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="meta">@interface</span> MyAnnotation{</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>此时的注解MyAnnotation可使用在任何地方(此时没有限定使用范围 )</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@MyAnnotation</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">test</span><span class="params">()</span>{</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<span id="more"></span>
<ul>
<li>注解定义1(带值的注解)</li>
</ul>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="meta">@interface</span> MyAnnotation{</span><br><span class="line"> String <span class="title function_">value</span><span class="params">()</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>此时的注解MyAnnotation带有参数,注解是需要带上参数</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@MyAnnotation(value="VALUE")</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">test</span><span class="params">()</span>{</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>如果将通过default 指定默认值,则在使用注解时,可省去value的值,此时使用默认值”DEFAULT”,如下:<br></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="meta">@interface</span> MyAnnotation{</span><br><span class="line"> String <span class="title function_">value</span><span class="params">()</span> <span class="keyword">default</span> <span class="string">"DEFAULT"</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@MyAnnotation</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">test</span><span class="params">()</span>{</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h5 id="元注解"><a href="#元注解" class="headerlink" title="元注解"></a>元注解</h5><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">注解的注解,用来注解所定义的注解</span><br><span class="line">@Target </span><br><span class="line"> 枚举ElementType有ANNOTATION_TYPE, CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD,</span><br><span class="line"> PACKAGE, PARAMETER, TYPE。</span><br><span class="line"> TYPE: 适用于class,interface,enum</span><br><span class="line"> FIELD: 适用于field</span><br><span class="line"> METHOD: 适用于methond</span><br><span class="line"> PARAMETER: 适用于methond上的parameter</span><br><span class="line"> CONSTRUCTOR: 适用于constructor</span><br><span class="line"> LOCAL_VARIABLE: 适用于局部变量</span><br><span class="line"> ANNOTATION_TYPE: 适用于annotation</span><br><span class="line"> PACKAGE: 适用于package</span><br><span class="line">@Retention</span><br><span class="line"> 枚举RetentionPolicy有CLASS,RUNTIME,SOURCE三种枚举值。</span><br><span class="line"> CLASS: 注解会被编译器保留在class文件中,但不会被VM读取。</span><br><span class="line"> RUNTIME: 注解会被编译器保留在class文件中,会被VM在运行时获取,因此能被反射机制读取。</span><br><span class="line"> SOURCE: 注解会被编译器丢弃。</span><br><span class="line"> 默认值为CLASS。</span><br></pre></td></tr></table></figure>
<ul>
<li>注解定义2(指定注解范围)</li>
</ul>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Target(ElementType.METHOD)</span></span><br><span class="line"><span class="meta">@Retention(RetentionPolicy.RUNTIME)</span></span><br><span class="line"><span class="keyword">public</span> <span class="meta">@interface</span> MyAnnotation{</span><br><span class="line"> String <span class="title function_">value</span><span class="params">()</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<ul>
<li>注解定义3(指定保持状态)</li>
</ul>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Retention(RetentionPolicy.RUNTIME)</span></span><br><span class="line"><span class="keyword">public</span> <span class="meta">@interface</span> MyAnnotation{</span><br><span class="line"> String <span class="title function_">say</span><span class="params">()</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>当为RetentionPolicy.RUNTIME,那么问题来了,我们可以通过反射机制,在运行时来获取注解信息</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TestAnnotation</span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">TestAnnotation</span><span class="params">()</span>{</span><br><span class="line"> AnnotationHelper.register(<span class="built_in">this</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="meta">@MyAnnotation(say="TEST")</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">test</span><span class="params">()</span>{</span><br><span class="line"> System.out.println(<span class="string">"TestAnnotation test()"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">AnnotationHelper</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">register</span><span class="params">(Object obj)</span>{<span class="comment">//此处通过反射来操作注解的对象</span></span><br><span class="line"> Class<?> clz=obj.getClass();</span><br><span class="line"> <span class="keyword">for</span>(Method m:clz.getDeclaredMethods()){</span><br><span class="line"> MyAnnotation ma=m.getAnnotation(MyAnnotation.class);</span><br><span class="line"> <span class="keyword">if</span>(ma!=<span class="literal">null</span>){</span><br><span class="line"> System.out.println(ma.say());<span class="comment">//输出注解的say值</span></span><br><span class="line"> } </span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MainTest</span>{</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] agrs)</span>{</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">TestAnnotation</span>().test();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>输出结果为:TEST</p>
]]></content>
<categories>
<category>Android</category>
</categories>
</entry>
<entry>
<title>JupyterLab NoteBook 安装</title>
<url>/2021/03/07/JupyterLab%20NoteBook%20%E5%AE%89%E8%A3%85/</url>
<content><![CDATA[<h3 id="1-安装python3虚拟环境"><a href="#1-安装python3虚拟环境" class="headerlink" title="1. 安装python3虚拟环境"></a>1. 安装python3虚拟环境</h3><p>此步骤根据需求而定,为了不影响系统Python环境,这里建立了虚拟环境。</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">cd ~</span><br><span class="line">python3 -m venv .p3env</span><br><span class="line">source ~/.p3env/bin/activate</span><br></pre></td></tr></table></figure>
<h3 id="2-修改pip源"><a href="#2-修改pip源" class="headerlink" title="2 修改pip源"></a>2 修改pip源</h3><p>为了能加速下载Python依赖,这里修改了pip源,这步也可根据自己的需求来。<br>可参考清华大学的pip源设置:<a href="https://mirrors.tuna.tsinghua.edu.cn/help/pypi/">https://mirrors.tuna.tsinghua.edu.cn/help/pypi/</a></p>
<h4 id="临时设置"><a href="#临时设置" class="headerlink" title="临时设置"></a>临时设置</h4><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">pip install -i https://pypi.tuna.tsinghua.edu.cn/simple some-package</span><br></pre></td></tr></table></figure>
<h4 id="全局设置"><a href="#全局设置" class="headerlink" title="全局设置"></a>全局设置</h4><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple</span><br></pre></td></tr></table></figure>
<span id="more"></span>
<p>可以在 <code>~/.config/pip/pip.conf</code> 中找到pip全局配置</p>
<figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line">[<span class="string">global</span>]</span><br><span class="line"><span class="string">index-url</span> <span class="string">=</span> <span class="string">https://pypi.tuna.tsinghua.edu.cn/simple</span></span><br></pre></td></tr></table></figure>
<p>不过在安装时,发现jupyter-lab下载还是很慢,因为jupyter-lab使用的时Piwheels源。<br>我们可以在配置里再加上aliyun的源。当然按理也可以直接设置aliyun的源为全局主源。或者继续添加其他的 <code>extra-index-url</code> 都行。这里主要演示怎么修改pip源的方法。</p>
<figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line">[<span class="string">global</span>]</span><br><span class="line"><span class="string">index-url</span> <span class="string">=</span> <span class="string">https://pypi.tuna.tsinghua.edu.cn/simple</span></span><br><span class="line"><span class="string">extra-index-url=https://mirrors.aliyun.com/pypi/simple</span></span><br></pre></td></tr></table></figure>
<h3 id="3-安装jupyter-lab"><a href="#3-安装jupyter-lab" class="headerlink" title="3 安装jupyter-lab"></a>3 安装jupyter-lab</h3><p>安装jupyter-lab的方法有好几种,这里使用pip: <a href="https://jupyter.org/install">https://jupyter.org/install</a></p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">pip install jupyterlab</span><br></pre></td></tr></table></figure>
<h3 id="4-运行jupyter-lab"><a href="#4-运行jupyter-lab" class="headerlink" title="4 运行jupyter-lab"></a>4 运行jupyter-lab</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">cd workspace</span><br><span class="line">jupyter-lab</span><br></pre></td></tr></table></figure>
<p>在工作目录中执行,在桌面环境下,会直接打开浏览器: <a href="http://localhost:8888/lab">http://localhost:8888/lab</a><br>在非桌面环境:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">[I 2021-03-07 23:58:57.962 ServerApp] jupyterlab | extension was successfully linked.</span><br><span class="line">[I 2021-03-07 23:58:58.943 ServerApp] nbclassic | extension was successfully linked.</span><br><span class="line">[I 2021-03-07 23:58:59.044 LabApp] JupyterLab extension loaded from /home/pi/.p3env/lib/python3.7/site-packages/jupyterlab</span><br><span class="line">[I 2021-03-07 23:58:59.045 LabApp] JupyterLab application directory is /home/pi/.p3env/share/jupyter/lab</span><br><span class="line">[I 2021-03-07 23:58:59.054 ServerApp] jupyterlab | extension was successfully loaded.</span><br><span class="line">[I 2021-03-07 23:58:59.074 ServerApp] nbclassic | extension was successfully loaded.</span><br><span class="line">[I 2021-03-07 23:58:59.075 ServerApp] 启动notebooks 在本地路径: /home/user/.config/pip</span><br><span class="line">[I 2021-03-07 23:58:59.075 ServerApp] Jupyter Server 1.4.1 is running at:</span><br><span class="line">[I 2021-03-07 23:58:59.075 ServerApp] http://localhost:8888/lab</span><br><span class="line">[I 2021-03-07 23:58:59.076 ServerApp] or http://127.0.0.1:8888/lab</span><br><span class="line">[I 2021-03-07 23:58:59.076 ServerApp] 使用control-c停止此服务器并关闭所有内核(两次跳过确认).</span><br><span class="line">[W 2021-03-07 23:58:59.089 ServerApp] 没有找到web浏览器: could not locate runnable browser.</span><br></pre></td></tr></table></figure>
<p>即使在局域网打开 <a href="http://192.168.123.30:8888/">http://192.168.2.3:8888/</a> 也没用。<br>在非桌面环境下,可使用以下命令:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">jupyter-lab --no-browser --ip=0.0.0.0 </span><br></pre></td></tr></table></figure>
<p><code>--ip=x.x.x.x</code> 表示运行访问的主机IP地址, <code>0.0.0.0 </code> 表示所有主机都可访问。<br>这个时候打开<a href="http://192.168.123.30:8888/">http://192.168.2.3:8888/</a> 便可进入。</p>
<h3 id="5-配置外网环境"><a href="#5-配置外网环境" class="headerlink" title="5 配置外网环境"></a>5 配置外网环境</h3><p>在申请到公网IP,或者是运行在诸如VPS的云主机上时,需要对jupyter-lab进行配置。<br>由于公网访问,为了安全,我们对jupyter-lab设置密码。</p>
<h4 id="生成jupyter-lab配置文件"><a href="#生成jupyter-lab配置文件" class="headerlink" title="生成jupyter-lab配置文件"></a>生成jupyter-lab配置文件</h4><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">jupyter-lab --generate -config</span><br></pre></td></tr></table></figure>
<h4 id="修改配置文件"><a href="#修改配置文件" class="headerlink" title="修改配置文件"></a>修改配置文件</h4><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">cd ~/.jupyter</span><br><span class="line">vim jupyter_lab_config.py</span><br></pre></td></tr></table></figure>
<p>可以修改以下配置:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">c.ServerApp.password='xxxx'</span><br><span class="line">c.ServerApp.password_required = True</span><br><span class="line">c.ServerApp.port = 8888</span><br></pre></td></tr></table></figure>
<p>具体的修改项可以根据自己的需求来<br>其中鉴权方式分为2中,一种是密码,一种是服务器token,服务器token会由服务器随机生成,不建议采用这种方式。服务器token可以在 <code>~/.jupyter/jupyter_server_config.json</code> 文件末尾找到。<br>修改配置也可以通过命令行来进行,比较推荐这种方式。</p>
<h4 id="修改密码"><a href="#修改密码" class="headerlink" title="修改密码"></a>修改密码</h4><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">jupyter-lab password</span><br></pre></td></tr></table></figure>
<h4 id="修改工作目录"><a href="#修改工作目录" class="headerlink" title="修改工作目录"></a>修改工作目录</h4><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">jupyter-lab --app-dir=<Unicode></span><br></pre></td></tr></table></figure>
<h4 id="指端IP和端口号"><a href="#指端IP和端口号" class="headerlink" title="指端IP和端口号"></a>指端IP和端口号</h4><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">jupyter-lab --no-browser --ip=0.0.0.0 --port=5002</span><br></pre></td></tr></table></figure>
<p>具体由哪些方法见</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">jupyter-lab --help </span><br></pre></td></tr></table></figure>
<p>为了提高安全性,可使用ssl设置https,具体修改的参数见 <code>jupyter-lab --help </code> 或者 <code>jupyter_lab_config.py</code> 文件。下面我使用的是nginx来方向代理。</p>
<h3 id="6-Nginx配置"><a href="#6-Nginx配置" class="headerlink" title="6 Nginx配置"></a>6 Nginx配置</h3><p>Nginx的使用可见文档:<a href="https://www.cwiki.cn/archives/nginx%E4%BD%BF%E7%94%A8">https://www.cwiki.cn/archives/nginx%E4%BD%BF%E7%94%A8</a></p>
<h4 id="Nginx-配置文件"><a href="#Nginx-配置文件" class="headerlink" title="Nginx 配置文件"></a>Nginx 配置文件</h4><p>这里设置的端口是8080,可以按自己的需求,比如443,设置ssl证书。由于jupyter-lab会使用到websocket,需要进行设置。</p>
<figure class="highlight nginx"><table><tr><td class="code"><pre><span class="line"><span class="section">server</span> {</span><br><span class="line"> <span class="attribute">listen</span> <span class="number">8080</span> ssl;</span><br><span class="line"> <span class="attribute">listen</span> [::]:<span class="number">8080</span> ssl;</span><br><span class="line"></span><br><span class="line"> <span class="attribute">ssl_certificate</span> /path/xx.crt;</span><br><span class="line"> <span class="attribute">ssl_certificate_key</span> /path/xx.key;</span><br><span class="line"></span><br><span class="line"> <span class="attribute">server_name</span> xxx.yy.zz;</span><br><span class="line"></span><br><span class="line"> <span class="section">location</span> / {</span><br><span class="line"> <span class="attribute">proxy_pass</span> http://127.0.0.1:8888;</span><br><span class="line"> <span class="attribute">proxy_set_header</span> Host <span class="variable">$host</span>;</span><br><span class="line"> <span class="attribute">proxy_set_header</span> X-Real-Scheme <span class="variable">$scheme</span>;</span><br><span class="line"> <span class="attribute">proxy_set_header</span> X-Real-IP <span class="variable">$remote_addr</span>;</span><br><span class="line"> <span class="attribute">proxy_set_header</span> X-Forwarded-For <span class="variable">$proxy_add_x_forwarded_for</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment"># WebSocket support</span></span><br><span class="line"> <span class="attribute">proxy_http_version</span> <span class="number">1</span>.<span class="number">1</span>;</span><br><span class="line"> <span class="attribute">proxy_set_header</span> Upgrade <span class="variable">$http_upgrade</span>;</span><br><span class="line"> <span class="attribute">proxy_set_header</span> Connection <span class="string">"upgrade"</span>;</span><br><span class="line"></span><br><span class="line"> <span class="attribute">proxy_read_timeout</span> <span class="number">120s</span>;</span><br><span class="line"> <span class="attribute">proxy_next_upstream</span> <span class="literal">error</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h4 id="后台启动jupyter-lab"><a href="#后台启动jupyter-lab" class="headerlink" title="后台启动jupyter-lab"></a>后台启动jupyter-lab</h4><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">source ~/.p3env/bin/activate</span><br><span class="line">nohup jupyter-lab --no-browser --ip=0.0.0.0 > /path/x.log 2>&1 & # log </span><br><span class="line">nohup jupyter-lab --no-browser --ip=0.0.0.0 > /dev/null 2>&1 & # 无log </span><br></pre></td></tr></table></figure>
<p>关于后台运行可参考其他文章</p>
<h4 id="启动Nginx"><a href="#启动Nginx" class="headerlink" title="启动Nginx"></a>启动Nginx</h4><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">已经运行了nginx</span></span><br><span class="line">sudo service nginx reload</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">没运行</span></span><br><span class="line">sudo service nginx start</span><br></pre></td></tr></table></figure>
<p>这时在外网打开 <a href="https://xxxx:8080/lab">https://xxxx:8080/lab</a>,输入密码就可以进入</p>
<p>DONE</p>
]]></content>
<categories>
<category>机器学习</category>
</categories>
</entry>
<entry>
<title>Linux虚拟镜像创建分区和Grub2安装</title>
<url>/2021/03/27/Linux%E8%99%9A%E6%8B%9F%E9%95%9C%E5%83%8F%E5%88%9B%E5%BB%BA%E5%88%86%E5%8C%BA%E5%92%8CGrub2%E5%AE%89%E8%A3%85/</url>
<content><![CDATA[<h3 id="1-创建虚拟磁盘"><a href="#1-创建虚拟磁盘" class="headerlink" title="1. 创建虚拟磁盘"></a>1. 创建虚拟磁盘</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">dd if=/dev/zero of=15g.img bs=1M count=15360 # 15GB</span><br></pre></td></tr></table></figure>
<h3 id="2-挂载img"><a href="#2-挂载img" class="headerlink" title="2. 挂载img"></a>2. 挂载img</h3><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">sudo losetup -l # 查看当前loop设备</span><br><span class="line">sudo losetup /dev/loop0 15g.img # 挂在到空闲的loop0上</span><br></pre></td></tr></table></figure>
<h3 id="3-img分区"><a href="#3-img分区" class="headerlink" title="3. img分区"></a>3. img分区</h3><p>通过fdisk对img分区<br>执行:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">sudo fdisk /dev/loop0</span><br></pre></td></tr></table></figure>
<span id="more"></span>
<p>进入提示:</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">欢迎使用 fdisk (util-linux 2.34)。</span><br><span class="line">更改将停留在内存中,直到您决定将更改写入磁盘。</span><br><span class="line">使用写入命令前请三思。</span><br><span class="line"></span><br><span class="line">设备不包含可识别的分区表。</span><br><span class="line">创建了一个磁盘标识符为 0x7accf69c 的新 DOS 磁盘标签。</span><br><span class="line"></span><br><span class="line">命令(输入 m 获取帮助):</span><br></pre></td></tr></table></figure>
<p>输入m,查看帮助</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">命令(输入 m 获取帮助): m</span><br><span class="line"></span><br><span class="line">帮助:</span><br><span class="line"></span><br><span class="line"> DOS (MBR)</span><br><span class="line"> a 开关 可启动 标志</span><br><span class="line"> b 编辑嵌套的 BSD 磁盘标签</span><br><span class="line"> c 开关 dos 兼容性标志</span><br><span class="line"></span><br><span class="line"> 常规</span><br><span class="line"> d 删除分区</span><br><span class="line"> F 列出未分区的空闲区</span><br><span class="line"> l 列出已知分区类型</span><br><span class="line"> n 添加新分区</span><br><span class="line"> p 打印分区表</span><br><span class="line"> t 更改分区类型</span><br><span class="line"> v 检查分区表</span><br><span class="line"> i 打印某个分区的相关信息</span><br><span class="line"></span><br><span class="line"> 杂项</span><br><span class="line"> m 打印此菜单</span><br><span class="line"> u 更改 显示/记录 单位</span><br><span class="line"> x 更多功能(仅限专业人员)</span><br><span class="line"></span><br><span class="line"> 脚本</span><br><span class="line"> I 从 sfdisk 脚本文件加载磁盘布局</span><br><span class="line"> O 将磁盘布局转储为 sfdisk 脚本文件</span><br><span class="line"></span><br><span class="line"> 保存并退出</span><br><span class="line"> w 将分区表写入磁盘并退出</span><br><span class="line"> q 退出而不保存更改</span><br><span class="line"></span><br><span class="line"> 新建空磁盘标签</span><br><span class="line"> g 新建一份 GPT 分区表</span><br><span class="line"> G 新建一份空 GPT (IRIX) 分区表</span><br><span class="line"> o 新建一份的空 DOS 分区表</span><br><span class="line"> s 新建一份空 Sun 分区表</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">命令(输入 m 获取帮助):</span><br></pre></td></tr></table></figure>