blob: f55f6de50fd931b791f1aa5715afbdd6cd698ba2 [file] [log] [blame] [view]
Tommy C. Li68f0ba52019-03-18 17:24:101# How to Write Cross-Platform UI (Native components)
2
3[TOC]
4
5Chrome runs on many platforms such as Desktop (Windows, Mac, Linux, and
6ChromeOS), Android, iOS, and VR. These platforms have different UIs, written in
7different languages. Chrome also has WebUI, which is browser UI implemented in
8the HTML content area. This can be considered another UI toolkit.
9
10## Separating out platform-independent business logic
11
12For UI that appears on multiple platforms, it's best to share as much of the
13business logic (model behavior backing the UI) as possible. The
14platform-specific views should be as minimal and "dumb" as possible. One caveat:
15sharing everything may not be feasible if there are performance or latency
16concerns.
17
18The cross-platform model will be in native C++ code, likely in the
19//components/foobar directory. Model layer code should handle the business
20logic, and be richly observable. Platform-specific views/controllers should
21observe the model, update the UI, and mutate the model as needed. This model
22should have tests.
23
24Note that there can be model state that is applicable to only a subset of
25platforms. For instance, mobile devices can change device rotation or layout. On
26Mobile, the platform itself may provide extended text editing capabilities that
27don't exist on Desktop.
28
29## Lifetime Issues
30
31Different platforms may have different UI lifetime semantics, so it's helpful to
32keep the business logic stateless or with a flexible lifetime model. Android
33Java object lifetimes are well-defined, but has gotchas for cross-platform code.
34For instance: the Java side of Android is available immediately on startup, but
35the C++ side needs to wait for the native library to be loaded. Having a native
36object "own" a garbage-collected Java object or vice versa can also be tricky.
37
38 1. Pure static functions are the easiest, if this works for your use case. In
39 addition to being easy to bridge to Java, these are also easy to unit test,
40 since they don't require setting up state.
41
42 You can usually use pure static functions for simpler cases that don't
43 involve state. These are easy to bridge to Java. See
44 [`UrlFormatter`](https://cs.chromium.org/chromium/src/components/url_formatter/android/java/src/org/chromium/components/url_formatter/UrlFormatter.java)
45 for an example of this.
46
47 2. For objects that are associated with a specific `Profile`, use a
48 `KeyedService` instance with
49 [`BrowserContextKeyedServiceFactory`](https://cs.chromium.org/chromium/src/components/keyed_service/content/browser_context_keyed_service_factory.h).
50 If your object depends on other `KeyedService` instances, there's a strong
51 chance your object should also be a `KeyedService`.
52
53 These are also pretty easy to bridge to Java. In most cases, the Java code
54 will need to pass a `Profile` object, so that the native `KeyedService` can
55 be fetched.
56
57 A neat trick is that the Java code can be all-static, even if the native
58 code isn't, if every method also includes a `Profile` parameter.
59
60 3. Objects tied to WebContents lifetimes are also commonly used, and can be
61 implemented using a WebContentsObserver and WebContentsUserData.
62
63 4. For lifetimes tied to UI instances, or other custom lifetimes, you will need
64 to do custom lifetime management. For Java bridging advice, see the JNI
65 documentation for details.
66
67## More Advice on Bridging to Java
68
69Bridging a code module to Java will have three parts:
70
71 1. components/omnibox/browser/foobar.h/cc - Cross-platform code you already
72 wrote and have unit tests for.
73
74 2. chrome/browser/android/omnibox/foo_feature_android.h/cc - C++ side of the
75 bridge. You might only need the cc file.
76
77 3. chrome/android/java/src/org/chromium/chrome/browser/omnibox/FooFeature.java
78 - Java side of the bridge.
79
80See the [JNI README](../base/android/jni_generator/README.md) for more details.