You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+33-41Lines changed: 33 additions & 41 deletions
Original file line number
Diff line number
Diff line change
@@ -49,57 +49,49 @@ component must be included in your app's build to support `rustls-platform-verif
49
49
`rustls-platform-verifier` bundles the required native components in the crate, but the project must be setup to locate them
50
50
automatically and correctly.
51
51
52
-
Firstly, create an [init script](https://docs.gradle.org/current/userguide/init_scripts.html) in your Android
53
-
Gradle project, with a filename of `init.gradle`. This is generally placed in your project's root. In your project's `settings.gradle`, add these lines:
52
+
Inside of your project's `build.gradle` file, add the following code and Maven repository definition. `$PATH_TO_DEPENDENT_CRATE` is
53
+
the relative path to the Cargo manifest (`Cargo.toml`) of any crate in your workspace that depends on `rustls-platform-verifier` from
54
+
the location of your `build.gradle` file:
54
55
55
56
```groovy
56
-
apply from: file("./init.gradle");
57
-
// Cargo automatically handles finding the downloaded crate in the correct location
Next, the `rustls-platform-verifier` external dependency needs to be setup. Open the `init.gradle` file and add the following:
64
-
`$PATH_TO_DEPENDENT_CRATE` is the relative path to the Cargo manifest (`Cargo.toml`) of any crate in your workspace that depends on `rustls-platform-verifier`
65
-
from the location of your `init.gradle` file.
66
-
67
-
Alternatively, you can use `cmdProcessBuilder.directory(File("PATH_TO_ROOT"))` to change the working directory instead.
//! This crate is an implementation detail of the actual [rustls-platform-verifier](https://github.com/rustls/rustls-platform-verifier) crate.
4
+
//!
5
+
//! It contains no Rust code and is solely intended as a convenient delivery mechanism for the supporting Kotlin code that the main crate
6
+
//! requires to perform TLS certificate validation using Android's APIs.
7
+
//!
8
+
//! Other crates should not directly depend on this crate in any way, as nothing about it is considered stable and probably useless elsewhere.
9
+
//!
10
+
//! ## Details
11
+
//!
12
+
//! Note: Everything in this section is subject to change at any time. Semver may not be followed either.
13
+
//!
14
+
//! ### Why?
15
+
//!
16
+
//! It was the best middle ground between several tradeoffs. The important ones, in priority order, are:
17
+
//! - Automatically keeping component versions in sync
18
+
//! - Allowing well-tested and well-known `cargo` dependency management patterns to apply everywhere
19
+
//! - Providing a smooth developer experience as an Android consumer of `rustls-platform-verifier`
20
+
//!
21
+
//! Firstly, what alternatives are available for distributing the component? The other two known are source distribution n some form (here, it will be through crates.io)
22
+
//! and Maven Central. Starting with the first, its become infeasible due to toolchain syncing requirements. If the Android component is
23
+
//! built as part of the host app's Gradle build, then it becomes subject to any Gradle or AGP incompatibilites/requirements. In practice this means
24
+
//! the AGP version between this project and the main application have to match all the time. Sometimes this works, but it becomes challenging/unfeasible
25
+
//! during yearly toolchain/SDK upgrades and is not maintainable long term. Note that this is the _only_ option in this section which retains compatible
26
+
//! with Cargo's Git dependency patching.
27
+
//!
28
+
//! Next, Maven Central. This is considered the standard way of distributing public Android dependencies. There are two downsides to this
29
+
//! approach: version synchronization and publishing overhead. Version syncing is the hardest part: There's not a good way to know what version
30
+
//! a crate is that doesn't hurt the Cargo part of the build or damage functionality. So instead of making assumptions at runtime, we would need to do
31
+
//! clunky and manual version counting with an extra error case. Less importantly, the admin overhead of Maven Central is non-zero so its good to avoid
32
+
//! if possible for such a small need.
33
+
//!
34
+
//! It is also worth calling out a third set of much worse options: requiring users to manually download and install the Android component
35
+
//! on each update, which magnifies the version syncing problem with lots of user overhead and then deleting the component outright. A rewrite
36
+
//! could be done with raw JNI calls, but this would easily be 3x the size of the existing implementation and require huge amounts of `unsafe`
37
+
//! to review then audit.
38
+
//!
39
+
//! ### The solution
40
+
//!
41
+
//! The final design was built to avoid the pitfalls the previous two options mentioned. To build it, we rely on CI and packaging scripts to build
42
+
//! the Android component into a prebuilt AAR file before creating a release. Next, a [on-disk Maven repository](https://maven.apache.org/repositories/local.html)
43
+
//! is hosted inside of this repository. Only the unchanging file structure of it is kept checked-in, to avoid churn. The remaining parts are filled in
44
+
//! during the packaging/release process, before being included in `cargo package` via an `include` Cargo.toml directive. Finally, once the repository has had
45
+
//! its artifacts added, this crate is published to crates.io containing it. Then, the main crate ensures its downloaded when an Android target is compiled for via
46
+
//! a platform-specific dependency.
47
+
//!
48
+
//! On the Gradle side, we include a very small snippet of code for users to include in their `settings.gradle` file to dyanmically locate the local maven repository
49
+
//! on disk automatically based off Cargo's current version of it. The script is configuration cache friendly and doesn't impact performance either. When the script
50
+
//! is run, it finds the cargo-cached download of the crate and tells Gradle it can find the `rustls-platform-verifier` Android component there when it gets sourced
51
+
//! into the hosting application's build tree.
52
+
//!
53
+
//! ### Precompiled artifacts?
54
+
//!
55
+
//! For some, the notion of shipping something pre-compiled with an existing source distribution might seem incorrect, or insecure. However in this specific case,
56
+
//! putting aside the fact shipping Kotlin code doesn't work (see above), there are many reasons this isn't the case:
57
+
//! - Shipping pre-compiled artifacts is normal in the Java ecosystem. Maven Central and other package repositories do the same thing and serve `.jar` downloads.
58
+
//! - Those not using Android will never download the pre-compiled AAR file.
59
+
//! - The artifacts are incredibly easy to reproduce given an identicial compilation toolchain.
60
+
//! - The artifacts are not native executables, or raw `.jar` files, so they can't be accidentally executed on a host system.
61
+
//!
62
+
//! ## Summary
63
+
//!
64
+
//! In summary, the selected distribution method avoids most of the previous pitfalls while still balancing a good experience for `cargo` annd Gradle users. Some of its
65
+
//! positive properties include:
66
+
//! - Full compatibility with Cargo's dependency management, including Git patching[^1]
67
+
//! - No version checking or synchronization required
68
+
//! - Painless and harmless to integrate into an Android app's build system
69
+
//! - Low maintenance for the main crate maintainers'
70
+
//!
71
+
//! [^1]: The Git reference being used must have the local maven repository built and checked-in first.
0 commit comments