Dart 对 Native 的支持目前还不是很完善,Flutter 团队目前开发的 Tonic 库很好的去支持 Dart 与 C/C++ 代码的相互调用。Tonic 的代码仓库地址在这里。 A collection of C++ utilities for working with the DartVM API. 通过 Tonic 可以完整实现 Dart 与 C++ 之间的代码交互。
We wanted a standard way to build the projects, a clear definition of what the project consisted of, an easy way to publish project information and a way to share JARs across several projects.
Maven 提供了一种隐性依赖的方式将间接依赖的三方库像直接依赖一样,举例来说,项目 A 依赖了项目 B ,项目 B 依赖了项目 C ,那项目 A 就像直接依赖了项目 C 一样使用项目 C 对外暴露的功能。不过在一个大型的项目管理中,错综复杂的依赖关系会导致依赖传递过程中出现的各种依赖冲突。一般地,我们可以通过 dependencyManagement 在根项目中指定项目的版本,如果没有指定,Maven 将按照默认提供的依赖仲裁法案对于版本号不一致的项目进行科学仲裁,这跟 Gradle 中默认选择最高版本的做法不太一致,这种仲裁有两个原则: 一、就近原则,根据项目依赖深度选择最近依赖的版本;
A -> B -> C 2.0
A -> C 1.0
通过就近原则,最终 A 依赖 C 的是 1.0 的版本。
二、优先声明原则,如果路径深度一致,则选择最先声明的版本。
A -> B -> C 2.0
A -> D -> C 1.0
通过优先声明原则,最终 A 依赖 C 的是 2.0 的版本。
./gradlew hello Starting a Gradle Daemon (subsequent builds will be faster) Parallel execution with configuration on demand is an incubating feature. :hello Hi from Gradle
class Person { String personName = '李四' int personAge = 18 def printPerson(){ println "name is ${personName},age is ${personAge}" } } def person(Closure<Person> closure){ Person p = new Person(); closure.delegate = p //委托模式优先 closure.setResolveStrategy(Closure.DELEGATE_FIRST); return closure }
The list of Application variants. Since the collections is built after evaluation, it should be used with Gradle’s all iterator to process future items.
All product flavors used by this project. 渠道包的列表,可以覆盖defaultConfig的参数配置,形成自己的风味
flavorDimensionList
The names of flavor dimensions. 添加维度的定义,维度的使用上面defaultConfig已经有说明了。
resourcePrefix
A prefix to be used when creating new resources. Used by Android Studio. 在模块化开发中比较重要,给每个模块指定一个特定的资源前缀,可以避免多模块使用相同的文件命名后合并冲突,在build.gradle中指定了这个配置后,AS会检查不合法的资源命名并报错。
All source sets. Note that the Android plugin uses its own implementation of source sets, AndroidSourceSet.An AndroidSourceSet represents a logical group of Java, aidl and RenderScript sources as well as Android and non-Android (Java-style) resources.
if (flavorName.contains("360") && buildTypeName.contains("debug")) { // Tells Gradle to ignore each variant that satisfies the conditions above. setIgnore(true) } }
LibraryExtension
libraryVariants
The list of library variants. Since the collections is built after evaluation, it should be used with Gradle’s all iterator to process future items.
android.libraryVariants.all { variant -> def mergedFlavor = variant.getMergedFlavor() // Defines the value of a build variable you can use in the manifest. mergedFlavor.manifestPlaceholders = [hostName:"www.example.com"] }
public static User fromJson(String json, final User old) { try { JSONObject object = new JSONObject(json); long id = object.getLong("id"); if (id == old.getId()) { Gson gson = new GsonBuilder().registerTypeAdapter(User.class, new InstanceCreator<User>() { @Override public User createInstance(Type type) { return old; } }).create(); return gson.fromJson(json, User.class); } } catch (JSONException e) { e.printStackTrace(); } return new Gson().fromJson(json, User.class); }
public static List<User> fromJson(String json, final List<User> old) { try { List<User> result = new ArrayList<>(); JSONArray array = new JSONArray(json); for (int i = 0; i < array.length(); i++) { JSONObject object = array.getJSONObject(i); final long id = object.getLong("id"); Gson gson = new GsonBuilder().registerTypeAdapter(User.class, new InstanceCreator<User>() { @Override public User createInstance(Type type) { return getUserById(old, id); } }).create(); result.add(gson.fromJson(object.toString(), User.class)); } return result; } catch (JSONException e) { e.printStackTrace(); } return new Gson().fromJson(json, new TypeToken<List<User>>() { }.getType()); }
private static User getUserById(List<User> users, long id) { for (User user : users) { if (user.getId() == id) { return user; } } return new User(); } }
debugFlutterJar = new File('flutter-jars/debug/flutter.jar') profileFlutterJar = new File('flutter-jars/profile/flutter.jar') releaseFlutterJar = new File('flutter-jars/release/flutter.jar') dynamicProfileFlutterJar = new File('flutter-jars/dynamicProfile/flutter.jar') dynamicReleaseFlutterJar = new File('flutter-jars/dynamicRelease/flutter.jar')
HTTPS (also called HTTP over Transport Layer Security (TLS), HTTP over SSL, and HTTP Secure) is a communications protocol for secure communication over a computer network which is widely used on the Internet. HTTPS consists of communication over Hypertext Transfer Protocol (HTTP) within a connection encrypted by Transport Layer Security, or its predecessor, Secure Sockets Layer. The main motivation for HTTPS is authentication of the visited website and protection of the privacy and integrity of the exchanged data.
其实也很简单,我们把服务端的证书内置在我们的APP里,我们在做服务端证书校验的时候只比对是否和这个证书完全相同,不同就直接抛错,那中间人便没有办法绕过证书进行攻击。但是这里面也有一个问题就是服务端的证书可能会过期或者升级,而且服务端往往为了提高网络的安全性,证书的有效时间不会设置太长,这样APP就会因为这个证书的事情频繁发版,也很痛苦。(前段时间我司IOS的APP就是因为授权企业用户的证书没有及时更新,导致大家无法正常打开APP,血的教训导致我们不想重走这条路)可能你又想到了,我们可以把证书配置在后端,有更新的时候直接去下载不就完了,那我们的证书下载没有没拦截的风险吗,一旦拦截,我们所有的证书校验都会失效,比直接信任手机内置的证书更可怕。我们既不想只信任我们服务器的证书,又不想信任手机上所有的 CA 证书。有个不错的的信任方式是把签发我们服务器的证书的根证书导出打包到APP中,这样虽然不能做到百分之百的证书无漏洞,但是相比于信任手机中几百个证书,我们只信任一个风险会小很多,这也就是我们的QA妹子用Charles抓不了我们的包的原因。~~~
OkHttp attempts to balance two competing concerns:
Connectivity to as many hosts as possible. That includes advanced hosts that run the latest versions of boringssl and less out of date hosts running older versions of OpenSSL.
Security of the connection. This includes verification of the remote webserver with certificates and the privacy of data exchanged with strong ciphers.