-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
2304 lines (1033 loc) · 57.7 KB
/
Copy pathindex.html
File metadata and controls
2304 lines (1033 loc) · 57.7 KB
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
<!DOCTYPE html>
<html class="theme-next pisces use-motion" lang="zh-Hans">
<head>
<meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
<meta name="theme-color" content="#222">
<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />
<link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />
<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />
<link href="/css/main.css?v=5.1.4" rel="stylesheet" type="text/css" />
<link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png?v=5.1.4">
<link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png?v=5.1.4">
<link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png?v=5.1.4">
<link rel="mask-icon" href="/images/logo.svg?v=5.1.4" color="#222">
<meta name="keywords" content="Hexo, NexT" />
<meta property="og:type" content="website">
<meta property="og:title" content="陈明亮的 Blog">
<meta property="og:url" content="https://cmlgithub.github.io##定义网站访问的域名/index.html">
<meta property="og:site_name" content="陈明亮的 Blog">
<meta property="og:locale" content="zh-Hans">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="陈明亮的 Blog">
<script type="text/javascript" id="hexo.configurations">
var NexT = window.NexT || {};
var CONFIG = {
root: '/',
scheme: 'Pisces',
version: '5.1.4',
sidebar: {"position":"left","display":"post","offset":12,"b2t":false,"scrollpercent":false,"onmobile":false},
fancybox: true,
tabs: true,
motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
duoshuo: {
userId: '0',
author: '博主'
},
algolia: {
applicationID: '',
apiKey: '',
indexName: '',
hits: {"per_page":10},
labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
}
};
</script>
<link rel="canonical" href="https://cmlgithub.github.io##定义网站访问的域名/"/>
<title>陈明亮的 Blog</title>
<script type="text/javascript">
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?8fd4ada0332dc388c37d7285dc41b0a1";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</head>
<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">
<div class="container sidebar-position-left
page-home">
<div class="headband"></div>
<header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
<div class="header-inner"><div class="site-brand-wrapper">
<div class="site-meta ">
<div class="custom-logo-site-title">
<a href="/" class="brand" rel="start">
<span class="logo-line-before"><i></i></span>
<span class="site-title">陈明亮的 Blog</span>
<span class="logo-line-after"><i></i></span>
</a>
</div>
<p class="site-subtitle"></p>
</div>
<div class="site-nav-toggle">
<button>
<span class="btn-bar"></span>
<span class="btn-bar"></span>
<span class="btn-bar"></span>
</button>
</div>
</div>
<nav class="site-nav">
<ul id="menu" class="menu">
<li class="menu-item menu-item-home">
<a href="/" rel="section">
<i class="menu-item-icon fa fa-fw fa-home"></i> <br />
首页
</a>
</li>
<li class="menu-item menu-item-about">
<a href="/about/" rel="section">
<i class="menu-item-icon fa fa-fw fa-user"></i> <br />
关于
</a>
</li>
<li class="menu-item menu-item-tags">
<a href="/tags/" rel="section">
<i class="menu-item-icon fa fa-fw fa-tags"></i> <br />
标签
</a>
</li>
<li class="menu-item menu-item-archives">
<a href="/archives/" rel="section">
<i class="menu-item-icon fa fa-fw fa-archive"></i> <br />
归档
</a>
</li>
</ul>
</nav>
</div>
</header>
<main id="main" class="main">
<div class="main-inner">
<div class="content-wrap">
<div id="content" class="content">
<section id="posts" class="posts-expand">
<article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
<div class="post-block">
<link itemprop="mainEntityOfPage" href="https://cmlgithub.github.io##定义网站访问的域名/2022/12/02/ViewBinding的使用及原理/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="name" content="cml">
<meta itemprop="description" content="">
<meta itemprop="image" content="https://avatars1.githubusercontent.com/u/13469575?s=460&v=4">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="陈明亮的 Blog">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/2022/12/02/ViewBinding的使用及原理/" itemprop="url">ViewBinding的使用及原理</a></h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建于" itemprop="dateCreated datePublished" datetime="2022-12-02T08:25:44+08:00">
2022-12-02
</time>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h1 id="ViewBinding的使用及原理"><a href="#ViewBinding的使用及原理" class="headerlink" title="ViewBinding的使用及原理"></a>ViewBinding的使用及原理</h1><h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>1.findViewById</p>
<p>作为 Android 开发人员,没有不知道 findViewById 的。</p>
<p>想要操作视图中的控件,都需要先用到 findViewById 来找到这个控件,然后就可以对齐进行一系列的操作了(如:改变属性、设置监听、添加动画)。</p>
<p>缺点:当 xml 视图中控件较多时,代码中的 findViewById 也相应的越来越多。</p>
<p>2.ButterKnife</p>
<p>通过注解的方式来完成布局文件的绑定,从而避免写 findViewById 来提高效率。</p>
<p>示例:</p>
<pre><code>@BindView(R.id.tv_content)
TextView tvContent;
</code></pre><p>缺点:(其实也不能算缺点,只是时代在发展)在如今组件化随处可见的时期,使用 ButterKnife 就有点麻烦了,在 library 中需要将 R 修改为 R2 才可,这时候当 module 在 application 和 library 切换时就比较麻烦了。</p>
<p>3.kotlin-android-extensions</p>
<p>作为很多人初始接触 Kotlin 的一个入门操作,最初都是因为使用 kotlin-android-extensions 简便而用上了 Kotlin。</p>
<p>使用确实很简单,在工程 build.gradle 文件中添加</p>
<pre><code>dependencies{
classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version"
}
</code></pre><p>然后在 module 的 build.gradle 中添加</p>
<pre><code>apply plugin: 'kotlin-android-extensions'
</code></pre><p>这时候就直接可以使用 xml 视图中的控件 id 来操作控件了</p>
<pre><code>tv_content.text = "Smaple"
</code></pre><p>缺点:<br>1.在模块之间不能通用,比如:业务模块中不能使用基础模块中的基础布局<br>2.由于不同的资源文件可以使用相同的控件 id 名称,会有一定的错误可能性。</p>
<p>由于上面的原因,所以有了 ViewBinding ,后面还有 DataBinding。<br>关于 DataBinding 可以参考笔者的这篇介绍:</p>
<h2 id="ViewBinding-的使用"><a href="#ViewBinding-的使用" class="headerlink" title="ViewBinding 的使用"></a>ViewBinding 的使用</h2><p>添加配置在 module 的 build.gradle </p>
<pre><code>android{
buildFeatures{
viewBinding true
}
}
</code></pre><p>之后在编译的时候就会为我们的所有 xml 文件生成对应的 Binding 类了,如:activity_main.xml 对应的 ActivityMainBinding。</p>
<p>使用也非常简单,Activity 如下:</p>
<pre><code>class MainActivity : AppCompatActivity() {
private lateinit var activityMainBinding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activityMainBinding = ActivityMainBinding.inflate(layoutInflater)
setContentView(activityMainBinding.root)
activityMainBinding.tv_content = "Smaple"
}
}
</code></pre><p>Fragment 如下:</p>
<pre><code>class MainFragment: Fragment() {
private var fragmentMainBinding: FragmentMainBinding? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
fragmentMainBinding = FragmentMainBinding.inflate(inflater, container, false)
return super.onCreateView(inflater, container, savedInstanceState)
}
// 注意:在这里将 Binding 对象置为 null,防止内存泄漏(因为 Fragment 存在的时间大于视图)
override fun onDestroyView() {
super.onDestroyView()
fragmentMainBinding = null
}
}
</code></pre><p>如果某个布局不想使用 ViewBinding ,也就是不生成对应的 xxxBinding 类,那么只需要在 xml 的根 View 中添加 <code>tools:viewBindingIgnore="true"</code>。</p>
<h2 id="ViewBinding-原理"><a href="#ViewBinding-原理" class="headerlink" title="ViewBinding 原理"></a>ViewBinding 原理</h2><p>原理追溯到本质上还是使用了 findViewById 来实现了绑定。</p>
<p>只不过这个过程是通过 gradle 插件来实现的,在编译的时候 gradle 插件会为每一个 xml 布局生成对应的 xxxBinding 类,当然如果某个 xml 中配置了 <code>tools:viewBindingIgnore="true"</code> 的话就会被插件跳过了。</p>
<p>ActivityMainBinding.java 源码如下:</p>
<pre><code>public final class ActivityMainBinding implements ViewBinding {
@NonNull
private final RelativeLayout rootView;
@NonNull
public final TextView tvContent;
private ActivityMainBinding(@NonNull RelativeLayout rootView, @NonNull TextView tvContent) {
this.rootView = rootView;
this.tvContent = tvContent;
}
@Override
@NonNull
public RelativeLayout getRoot() {
return rootView;
}
@NonNull
public static ActivityMainBinding inflate(@NonNull LayoutInflater inflater) {
return inflate(inflater, null, false);
}
@NonNull
public static ActivityMainBinding inflate(@NonNull LayoutInflater inflater,
@Nullable ViewGroup parent, boolean attachToParent) {
View root = inflater.inflate(R.layout.activity_main, parent, false);
if (attachToParent) {
parent.addView(root);
}
return bind(root);
}
@NonNull
public static ActivityMainBinding bind(@NonNull View rootView) {
// The body of this method is generated in a way you would not otherwise write.
// This is done to optimize the compiled bytecode for size and performance.
int id;
missingId: {
id = R.id.tv_content;
TextView tvContent = ViewBindings.findChildViewById(rootView, id);
if (tvContent == null) {
break missingId;
}
return new ActivityMainBinding((RelativeLayout) rootView, tvContent);
}
String missingId = rootView.getResources().getResourceName(id);
throw new NullPointerException("Missing required view with ID: ".concat(missingId));
}
}
</code></pre><p>可以看到,显示通过 inflate 方法得到了 View 对象,然后通过 bind 方法中通过 findViewById 完成了控件的绑定。</p>
<p>而 getRoot 方法其实就是对根 View 的返回。</p>
<h2 id="ViewBinding-封装"><a href="#ViewBinding-封装" class="headerlink" title="ViewBinding 封装"></a>ViewBinding 封装</h2><p>既然使用 ViewBinding 的套路是固定的,那么我们就可以将其抽取出来。</p>
<p>代码如下:</p>
<pre><code>abstract class BaseActivity<T: ViewBinding>: AppCompatActivity() {
lateinit var mViewBinding: T
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mViewBinding = getViewBinding()
setContentView(mViewBinding.root)
}
abstract fun getViewBinding(): T
}
</code></pre><p>使用如下:</p>
<pre><code>class SecondActivity: BaseActivity<ActivitySecondBinding>() {
override fun getViewBinding(): ActivitySecondBinding {
return ActivitySecondBinding.inflate(layoutInflater)
}
fun test(){
mViewBinding.tv_content = "Sample"
}
}
</code></pre>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</div>
</article>
<article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
<div class="post-block">
<link itemprop="mainEntityOfPage" href="https://cmlgithub.github.io##定义网站访问的域名/2022/08/10/Kotlin标准库函数/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="name" content="cml">
<meta itemprop="description" content="">
<meta itemprop="image" content="https://avatars1.githubusercontent.com/u/13469575?s=460&v=4">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="陈明亮的 Blog">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/2022/08/10/Kotlin标准库函数/" itemprop="url">Kotlin 标准库函数</a></h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建于" itemprop="dateCreated datePublished" datetime="2022-08-10T08:25:44+08:00">
2022-08-10
</time>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h1 id="Kotlin-标准库函数"><a href="#Kotlin-标准库函数" class="headerlink" title="Kotlin 标准库函数"></a>Kotlin 标准库函数</h1><h2 id="apply"><a href="#apply" class="headerlink" title="apply"></a>apply</h2><p>说明:可以当做<code>配置函数</code>,可以在其 lambda 中直接执行调用者的内部函数,方便对其进行配置,且会返回配置好的调用者。</p>
<p>示例代码:</p>
<pre><code>import java.io.File
//对 file 设置可读写
fun main(){
//不使用 apply
val file = File("path")
file.setReadable(true)
file.setWritable(true)
file.setExecutable(false)
//使用 apply
val file = File("path").apply{
setReadable(true)
setWritable(true)
setExecutable(false)
}
}
</code></pre><h2 id="let"><a href="#let" class="headerlink" title="let"></a>let</h2><p>说明:let 可以将调用者传入其 lambda 中,使用 it 来代表调用者,且 let 会返回 lambda 的最后一行。</p>
<p>示例代码:</p>
<pre><code>// 计算集合中第一个数的平方值
fun main(){
// 不使用 let
val firstElement = listOf(3,2,2).first()
val result = firstElement * firstElement
// 使用 let
val resutl = listOf(3,2,1).let{
it * it
}
}
</code></pre><h2 id="run"><a href="#run" class="headerlink" title="run"></a>run</h2><p>说明:run 函数基本上跟 apply 函数相似,只是在返回值上有所不同,run 不返回调用者,返回的是 lambda 的结果,也就是 true 或者 false。</p>
<p>示例代码:</p>
<pre><code>import java.io.File
// 判断 file 中是否包含指定字符串
fun main(){
//不使用 run
val file = File("path")
val fileContent = file.readText()
val containsResult = fileContent.contains("great")
//使用 run
val file = File("path")
val containsResult = file.run{
readText().contains("great")
}
}
</code></pre><p>扩展使用:</p>
<p>说明:run 函数也可以执行函数引用</p>
<p>示例代码:</p>
<pre><code>fun main(){
"Benjamin"
.run(::isLong)
.run(::showMessage)
.run(::println)
}
fun isLong(name: String) = name.length >= 5
fun showMessage(isLong: Boolean){
return if(isLong){
"Name is too long."
}else{
"Please rename."
}
}
</code></pre><h2 id="with"><a href="#with" class="headerlink" title="with"></a>with</h2><p>说明:with 在功能上与 run 函数一样,区别只是在调用方式上,with 是将调用者作为自己的参数传递进来的。</p>
<p>示例代码:</p>
<pre><code>run main(){
val resutl = with("Benjamin"){
lenth >= 10
}
}
</code></pre><h2 id="also"><a href="#also" class="headerlink" title="also"></a>also</h2><p>说明:also 的功能上同 let 一样,都是将调用者传递到 lambda 中,不同点是在返回值上,let 返回的是 lambda 的结果,而 also 的返回值是调用者。针对这个特点,also 就非常适合用在针对同一对象的连续调用上,比如:链式调用</p>
<p>示例代码:</p>
<pre><code>import java.io.File
fun main(){
var fileContent = ""
File("path")
.also{
print(it.name)
}.also{
fileContent = it.readContent()
}
println(fileContent)
}
</code></pre><h2 id="takeIf"><a href="#takeIf" class="headerlink" title="takeIf"></a>takeIf</h2><p>说明:takeIf 从功能上说有点类似于 if,需要根据其 lambda 中的表达式结果来决定返回值是什么,当lambda 中的表达式结果是 true 时,返回的是调用者,反之返回的是 null。</p>
<p>示例代码:</p>
<pre><code>import java.io.File
fun main(){
val fileContent = File("path").takeIf{
it.canRead() && it.canWrite()
}?.readContent()
}
</code></pre><h2 id="takeUnless"><a href="#takeUnless" class="headerlink" title="takeUnless"></a>takeUnless</h2><p>说明:跟 takeIf 相反,只有 lambda 中的返回值是 false 时,才会返回调用者对象,否则返回 null 。</p>
<p>示例代码:</p>
<pre><code>import java.io.File
fun main(){
val fileContent = File("path").takeUnless{
it.isHidden
}?.readContent()
}
</code></pre>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</div>
</article>
<article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
<div class="post-block">
<link itemprop="mainEntityOfPage" href="https://cmlgithub.github.io##定义网站访问的域名/2021/07/01/Charles代理抓包/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="name" content="cml">
<meta itemprop="description" content="">
<meta itemprop="image" content="https://avatars1.githubusercontent.com/u/13469575?s=460&v=4">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="陈明亮的 Blog">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/2021/07/01/Charles代理抓包/" itemprop="url">Charles 代理抓包</a></h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建于" itemprop="dateCreated datePublished" datetime="2021-07-01T11:09:28+08:00">
2021-07-01
</time>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h1 id="Charles-代理抓包"><a href="#Charles-代理抓包" class="headerlink" title="Charles 代理抓包"></a>Charles 代理抓包</h1><h2 id="HTTP"><a href="#HTTP" class="headerlink" title="HTTP"></a>HTTP</h2><p>1.在电脑上安装 <code>Charles</code></p>
<p>2.打开 <code>Charles --> Proxy --> Proxy Settings</code> 可以看到 Prot 在里面填入你想自定的端口号,如:8888、9999 ……</p>
<p>3.1 在手机上 <code>设置 --> 无线网络 --> 链接的 Wifi --> Wifi 的设置 --> 代理设置 --> 手动 --> 填入电脑的 IP 和上一步设置的端口号 Port --> 保存</code></p>
<pre><code>查看电脑 IP ,Mac:终端输入 ifconfig | grep inet
</code></pre><p>3.2 在 TV 上 通过 adb 链接 TV 之后,执行命令:<code>adb shell settings put global http_proxy ip_address:port</code>,将 <code>ip_address</code> 替换为电脑的 IP 和 第二部自定义的端口号即可</p>
<pre><code>//TV 上删除代理的命令,依次执行这三条
adb shell settings delete global http_proxy
adb shell settings delete global global_http_proxy_host
adb shell settings delete global global_http_proxy_port
</code></pre><p>4.接下来在设备上打开你想抓包的 App,它发生网络请求的时候,就可以在电脑上的 Charles 中看到了。</p>
<h2 id="HTTPS"><a href="#HTTPS" class="headerlink" title="HTTPS"></a>HTTPS</h2><p>1.在电脑上安装 <code>Charles</code></p>
<p>2.电脑安装根证书 <code>打开 Charles --> Help --> SSL Proxying --> Install Charles Root Certificate --> 双击进入证书详情,选择信任</code></p>
<p>3.1手机安装根证书 <code>Charles --> Help --> Install Charles Root Certificate on a Mobile Device or Remote Browser --> 里面会提供一个下载的网址 chls.pro/ssl --> 在浏览器中打开这个网址,下载证书 --> 安装到手机上 --> 手机的 wifi 上设置代理到电脑上 --> 再在电脑的 Charles --> Proxy --> SSL Proxying Settings --> 打勾Enable SSL Proxying --> add Host:*,Port:443 --> ok</code></p>
<p>3.2 在 TV 上安装证书</p>
<p>具体的在设备上安装证书的细节,可参考此文章<a href="https://cmlgithub.github.io/2021/06/30/Android%20TV%20Phone%20%E5%AE%89%E8%A3%85%20CA%20%E8%AF%81%E4%B9%A6/">Android TV 、Phone 安装 CA 证书</a></p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</div>
</article>
<article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
<div class="post-block">
<link itemprop="mainEntityOfPage" href="https://cmlgithub.github.io##定义网站访问的域名/2021/06/30/Android TV Phone 安装 CA 证书/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="name" content="cml">
<meta itemprop="description" content="">
<meta itemprop="image" content="https://avatars1.githubusercontent.com/u/13469575?s=460&v=4">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="陈明亮的 Blog">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/2021/06/30/Android TV Phone 安装 CA 证书/" itemprop="url">Android TV 、Phone 安装 CA 证书</a></h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建于" itemprop="dateCreated datePublished" datetime="2021-06-30T19:55:44+08:00">
2021-06-30
</time>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h1 id="Android-TV、Phone-安装-CA-证书"><a href="#Android-TV、Phone-安装-CA-证书" class="headerlink" title="Android TV、Phone 安装 CA 证书"></a>Android TV、Phone 安装 CA 证书</h1><h2 id="TV"><a href="#TV" class="headerlink" title="TV"></a>TV</h2><p>直接按照如下的命令执行</p>
<p>1.<code>openssl x509 -inform PEM -subject_hash_old -in <your certificate>.pem | head -n 1</code></p>
<p>将 <strong><code><your certificate>.pem</code></strong> 替换成你的证书全路径,执行之后会得到一个 hash 值,如:711d79cc </p>
<p>2.将你本地的 <strong><code>xxx.pem</code></strong> 证书 重命名为 上一步得到的 <code>hash.0</code>,如:<code>711d79cc.0</code></p>
<p>3.通过 adb 链接设备</p>
<p>4.<code>adb push hash.0 /system/etc/security/cacerts/hash.0</code></p>
<p>5.<code>adb shell chmod 644 /system/etc/security/cacerts/hash.0</code></p>
<p><font color="red"><strong>ps</strong> </font>: /system/etc/security/cacerts TV 设备的证书存储在此目录下,最终目的就是将需要安装的证书,push 到这里即代表已安装。</p>
<h2 id="Phone"><a href="#Phone" class="headerlink" title="Phone"></a>Phone</h2><p>手机上相对比较简单了,因为都有设置可以操作</p>
<p>1.将需要的证书下载到手机的 sd 卡</p>
<p>2.操作路径:<code>设置 --> 安全 --> 设备管理与凭证 --> 从存储盘安装 --> 输入密码 --> 确定</code>。不同品牌手机的操作路径名称可能不能,这时候可以利用手机设置的搜索功能,直接搜索凭证、存储盘安装等关键字就能找到了。 </p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</div>
</article>