Reorganise docs into subdirectory
|
@ -16,3 +16,5 @@ plugins:
|
||||||
- jekyll-seo-tag
|
- jekyll-seo-tag
|
||||||
|
|
||||||
search_enabled: true
|
search_enabled: true
|
||||||
|
|
||||||
|
source: ./geckoview
|
|
@ -1,29 +0,0 @@
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
|
|
||||||
{% if page.title %}
|
|
||||||
<meta name="title" content="{{ page.title }} - {{ site.title }}">
|
|
||||||
{% endif %}
|
|
||||||
{% if page.description %}
|
|
||||||
<meta name="description" content="{{ page.description }}">
|
|
||||||
{% elsif page.summary %}
|
|
||||||
<meta name="description" content="{{ page.summary }}">
|
|
||||||
{% else %}
|
|
||||||
<meta name="description" content="{{ site.description }}">
|
|
||||||
{% endif %}
|
|
||||||
{% if page.tags %}
|
|
||||||
<meta name="keywords" content="{{ page.tags | join: "," }}">
|
|
||||||
{% else %}
|
|
||||||
<meta name="keywords" content="{{ site.tags | join: "," }}">
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<title>{{ page.title }} - {{ site.title }}</title>
|
|
||||||
<link rel="stylesheet" href="{{ "/assets/css/just-the-docs.css" | absolute_url }}">
|
|
||||||
<link rel="stylesheet" href="{{ "/assets/css/geckoview.css" | absolute_url }}">
|
|
||||||
{% if site.search_enabled != nil %}
|
|
||||||
<script type="text/javascript" src="{{ "/assets/js/vendor/lunr.min.js" | absolute_url }}"></script>
|
|
||||||
{% endif %}
|
|
||||||
<script type="text/javascript" src="{{ "/assets/js/just-the-docs.js" | absolute_url }}"></script>
|
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
</head>
|
|
|
@ -1,7 +0,0 @@
|
||||||
|
|
||||||
<li class="navigation-list-item{% if page.url contains '/javadoc/mozilla-central/index.html' %} active{% endif %}">
|
|
||||||
<a href="{{ site.url }}{{ site.baseurl }}/javadoc/mozilla-central/index.html" class="navigation-list-link{% if page.url contains '/javadoc/mozilla-central/index.html' %} active{% endif %}">API Documentation</a>
|
|
||||||
</li>
|
|
||||||
<li class="navigation-list-item{% if page.url contains 'CHANGELOG' %} active{% endif %}">
|
|
||||||
<a href="{{ site.url }}{{ site.baseurl }}/javadoc/mozilla-central/org/mozilla/geckoview/doc-files/CHANGELOG" class="navigation-list-link{% if page.url contains 'CHANGELOG' %} active{% endif %}">API Changelog</a>
|
|
||||||
</li>
|
|
|
@ -1,46 +0,0 @@
|
||||||
<nav role="navigation" aria-label="Main navigation">
|
|
||||||
<ul class="navigation-list">
|
|
||||||
{% assign pages_list = site.html_pages | sort:"nav_order" %}
|
|
||||||
{% for node in pages_list %}
|
|
||||||
<!-- <div>{{node.title}} = {{node.nav_exclude}}</div> -->
|
|
||||||
{% unless node.nav_exclude %}
|
|
||||||
{% if node.parent == nil %}
|
|
||||||
<li class="navigation-list-item{% if page.url == node.url or page.parent == node.title or page.grand_parent == node.title %} active{% endif %}">
|
|
||||||
{% if page.parent == node.title or page.grand_parent == node.title %}
|
|
||||||
{% assign first_level_url = node.url | absolute_url %}
|
|
||||||
{% endif %}
|
|
||||||
<a href="{{ node.url | absolute_url }}" class="navigation-list-link{% if page.url == node.url %} active{% endif %}">{{ node.title }}</a>
|
|
||||||
{% if node.has_children %}
|
|
||||||
{% assign children_list = site.html_pages | sort:"nav_order" %}
|
|
||||||
<ul class="navigation-list-child-list ">
|
|
||||||
{% for child in children_list %}
|
|
||||||
{% if child.parent == node.title %}
|
|
||||||
<li class="navigation-list-item {% if page.url == child.url or page.parent == child.title %} active{% endif %}">
|
|
||||||
{% if page.url == child.url or page.parent == child.title %}
|
|
||||||
{% assign second_level_url = child.url | absolute_url %}
|
|
||||||
{% endif %}
|
|
||||||
<a href="{{ child.url | absolute_url }}" class="navigation-list-link{% if page.url == child.url %} active{% endif %}">{{ child.title }}</a>
|
|
||||||
{% if child.has_children %}
|
|
||||||
{% assign grand_children_list = site.html_pages | sort:"nav_order" %}
|
|
||||||
<ul class="navigation-list-child-list">
|
|
||||||
{% for grand_child in grand_children_list %}
|
|
||||||
{% if grand_child.parent == child.title %}
|
|
||||||
<li class="navigation-list-item {% if page.url == grand_child.url %} active{% endif %}">
|
|
||||||
<a href="{{ grand_child.url | absolute_url }}" class="navigation-list-link{% if page.url == grand_child.url %} active{% endif %}">{{ grand_child.title }}</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
{% endif %}
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
{% endif %}
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
{% endunless %}
|
|
||||||
{% endfor %}
|
|
||||||
{% include javadoc.html %}
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
|
@ -1,81 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
|
|
||||||
<html lang="en-us">
|
|
||||||
{% include head.html %}
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<div class="page-wrap">
|
|
||||||
<div class="side-bar">
|
|
||||||
<a href="{{ site.url }}{{ site.baseurl }}" class="site-title fs-6 lh-tight">
|
|
||||||
<img src="{{ site.url }}{{ site.baseurl }}/assets/geckoview_icon_fullcolor-green.png" title="GeckoView" alt="GeckoView" style="vertical-align:middle; width:60px; height:60px">
|
|
||||||
<span>GeckoView</span>
|
|
||||||
</a>
|
|
||||||
<span class="fs-3"><button class="js-main-nav-trigger navigation-list-toggle btn btn-outline" type="button" data-text-toggle="Hide">Menu</button></span>
|
|
||||||
<div class="navigation main-nav js-main-nav">
|
|
||||||
{% include nav.html %}
|
|
||||||
</div>
|
|
||||||
<footer role="contentinfo" class="site-footer">
|
|
||||||
<p class="text-small text-grey-dk-000 mb-0">This site uses <a href="https://github.com/pmarsceill/just-the-docs">Just the Docs</a>, a documentation theme for Jekyll.</p>
|
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
<div class="main-content-wrap">
|
|
||||||
<div class="page-header">
|
|
||||||
<div class="main-content">
|
|
||||||
{% if site.search_enabled != nil %}
|
|
||||||
<div class="search js-search">
|
|
||||||
<div class="search-input-wrap">
|
|
||||||
<input type="text" class="js-search-input search-input" tabindex="0" placeholder="Search {{ site.title }}" aria-label="Search {{ site.title }}" autocomplete="off">
|
|
||||||
<svg width="14" height="14" viewBox="0 0 28 28" xmlns="http://www.w3.org/2000/svg" class="search-icon"><title>Search</title><g fill-rule="nonzero"><path d="M17.332 20.735c-5.537 0-10-4.6-10-10.247 0-5.646 4.463-10.247 10-10.247 5.536 0 10 4.601 10 10.247s-4.464 10.247-10 10.247zm0-4c3.3 0 6-2.783 6-6.247 0-3.463-2.7-6.247-6-6.247s-6 2.784-6 6.247c0 3.464 2.7 6.247 6 6.247z"/><path d="M11.672 13.791L.192 25.271 3.02 28.1 14.5 16.62z"/></g></svg>
|
|
||||||
</div>
|
|
||||||
<div class="js-search-results search-results-wrap"></div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% if site.aux_links != nil %}
|
|
||||||
<ul class="list-style-none text-small mt-md-1 mb-md-1 pb-4 pb-md-0 js-aux-nav aux-nav">
|
|
||||||
{% for link in site.aux_links %}
|
|
||||||
<li class="d-inline-block my-0{% unless forloop.last %} mr-2{% endunless %}"><a href="{{ link.last }}">{{ link.first }}</a></li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="main-content js-main-content" tabindex="0">
|
|
||||||
{% unless page.url == "/" %}
|
|
||||||
{% if page.parent %}
|
|
||||||
<nav class="breadcrumb-nav">
|
|
||||||
<ol class="breadcrumb-nav-list">
|
|
||||||
{% if page.grand_parent %}
|
|
||||||
<li class="breadcrumb-nav-list-item"><a href="{{ first_level_url }}">{{ page.grand_parent }}</a></li>
|
|
||||||
<li class="breadcrumb-nav-list-item"><a href="{{ second_level_url }}">{{ page.parent }}</a></li>
|
|
||||||
{% else %}
|
|
||||||
<li class="breadcrumb-nav-list-item"><a href="{{ first_level_url }}">{{ page.parent }}</a></li>
|
|
||||||
{% endif %}
|
|
||||||
<li class="breadcrumb-nav-list-item"><span>{{ page.title }}</span></li>
|
|
||||||
</ol>
|
|
||||||
</nav>
|
|
||||||
{% endif %}
|
|
||||||
{% endunless %}
|
|
||||||
<div id="main-content" class="page-content" role="main">
|
|
||||||
{{ content }}
|
|
||||||
|
|
||||||
{% if page.has_children == true and page.has_toc != false %}
|
|
||||||
<hr>
|
|
||||||
<h2 class="text-delta">Table of contents</h2>
|
|
||||||
{% assign children_list = site.pages | sort:"nav_order" %}
|
|
||||||
<ul>
|
|
||||||
{% for child in children_list %}
|
|
||||||
{% if child.parent == page.title and child.title != page.title %}
|
|
||||||
<li>
|
|
||||||
<a href="{{ child.url | absolute_url }}">{{ child.title }}</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,10 +0,0 @@
|
||||||
$sidebar-color: #ededf0;
|
|
||||||
|
|
||||||
$body-text-color: #4a4a4f;
|
|
||||||
$body-heading-color: #2a2a2e;
|
|
||||||
$nav-child-link-color: #2a2a2e;
|
|
||||||
|
|
||||||
$link-color: #0060df;
|
|
||||||
$btn-primary-color: #003eaa;
|
|
||||||
|
|
||||||
$code-background-color: #ededf0;
|
|
Двоичные данные
assets/DisableInstantRun.png
До Ширина: | Высота: | Размер: 303 KiB |
Двоичные данные
assets/GeckoViewStructure.png
До Ширина: | Высота: | Размер: 30 KiB |
Двоичные данные
assets/LogInBugzilla.png
До Ширина: | Высота: | Размер: 302 KiB |
Двоичные данные
assets/LogInOrRegister.png
До Ширина: | Высота: | Размер: 18 KiB |
Двоичные данные
assets/LogInPhab.png
До Ширина: | Высота: | Размер: 153 KiB |
|
@ -1,6 +0,0 @@
|
||||||
/* There is some code in just-the-docs that completely breaks styling for code
|
|
||||||
* blocks, this is an attempt to fix that. */
|
|
||||||
code {
|
|
||||||
font-weight: inherit;
|
|
||||||
font-size: 80%;
|
|
||||||
}
|
|
Двоичные данные
assets/geckoview_icon_1color-black.png
До Ширина: | Высота: | Размер: 1.2 KiB |
Двоичные данные
assets/geckoview_icon_1color-green.png
До Ширина: | Высота: | Размер: 1.8 KiB |
Двоичные данные
assets/geckoview_icon_fullcolor-green.png
До Ширина: | Высота: | Размер: 3.7 KiB |
|
@ -1,12 +0,0 @@
|
||||||
---
|
|
||||||
---
|
|
||||||
{
|
|
||||||
{% for page in site.html_pages %}"{{ forloop.index0 }}": {
|
|
||||||
"id": "{{ forloop.index0 }}",
|
|
||||||
"title": "{{ page.title | xml_escape }}",
|
|
||||||
"content": "{{ page.content | markdownify | strip_html | xml_escape | remove: 'Table of contents' | strip_newlines | replace: '\', ' ' }}",
|
|
||||||
"url": "{{ page.url | absolute_url | xml_escape }}",
|
|
||||||
"relUrl": "{{ page.url | xml_escape }}"
|
|
||||||
}{% if forloop.last %}{% else %},
|
|
||||||
{% endif %}{% endfor %}
|
|
||||||
}
|
|
|
@ -1,112 +0,0 @@
|
||||||
---
|
|
||||||
layout: default
|
|
||||||
title: Configuring GeckoView for Automation
|
|
||||||
summary: How to set environment variables, Gecko arguments, and Gecko preferences for automation and debugging.
|
|
||||||
tags: [GeckoView,Gecko,mozilla,android,WebView,mobile,debugging,automation,config,configuration,environment,variables,arguments,preferences]
|
|
||||||
nav_exclude: true
|
|
||||||
exclude: true
|
|
||||||
---
|
|
||||||
## Table of contents
|
|
||||||
{: .no_toc .text-delta }
|
|
||||||
|
|
||||||
1. TOC
|
|
||||||
{:toc}
|
|
||||||
|
|
||||||
# Configuring GeckoView
|
|
||||||
|
|
||||||
GeckoView and the underlying Gecko engine have many, many options, switches, and toggles "under the hood". Automation (and to a lesser extent, debugging) can require configuring the Gecko engine to allow (or disallow) specific actions or features.
|
|
||||||
|
|
||||||
Some such actions and features are controlled by the [`GeckoRuntimeSettings`]({{ site.url }}{{ site.baseurl }}/javadoc/mozilla-central/org/mozilla/geckoview/GeckoRuntimeSettings.html) instance you configure in your consuming project. For example, remote debugging web content via the Firefox Developer Tools is configured by [`GeckoRuntimeSettings.Builder#remoteDebuggingEnabled`]({{ site.url }}{{ site.baseurl }}/javadoc/mozilla-central/org/mozilla/geckoview/GeckoRuntimeSettings.Builder.html#remoteDebuggingEnabled-boolean-)
|
|
||||||
|
|
||||||
Not all actions and features have GeckoView API interfaces. Generally, actions and features that do not have GeckoView API interfaces are not intended for broad usage. Configuration for these types of things is controlled by:
|
|
||||||
- environment variables in GeckoView's runtime environment
|
|
||||||
- command line arguments to the Gecko process
|
|
||||||
- internal Gecko preferences
|
|
||||||
|
|
||||||
Automation-specific configuration is generally in this category.
|
|
||||||
|
|
||||||
## Reading configuration from a file
|
|
||||||
|
|
||||||
When GeckoView is embedded into a debugabble application (i.e., when your manifest includes `android:debuggable="true"`), by default GeckoView reads configuration from a file named `/data/local/tmp/$PACKAGE-geckoview-config.yaml`. For example, if your Android package name is `com.yourcompany.yourapp`, GeckoView will read configuration from
|
|
||||||
```
|
|
||||||
/data/local/tmp/com.yourcompany.yourapp-geckoview-config.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
### Configuration file format
|
|
||||||
|
|
||||||
The configuration file format is [YAML](https://yaml.org). The following keys are recognized:
|
|
||||||
- `env` is a map from string environment variable name to string value to set in GeckoView's runtime environment
|
|
||||||
- `args` is a list of string command line arguments to pass to the Gecko process
|
|
||||||
- `prefs` is a map from string Gecko preference name to boolean, string, or integer value to set in the Gecko profile
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
# Contents of /data/local/tmp/com.yourcompany.yourapp-geckoview-config.yaml
|
|
||||||
|
|
||||||
env:
|
|
||||||
MOZ_LOG: nsHttp:5
|
|
||||||
|
|
||||||
args:
|
|
||||||
- --marionette
|
|
||||||
- --profile
|
|
||||||
- "/path/to/gecko-profile"
|
|
||||||
|
|
||||||
prefs:
|
|
||||||
foo.bar.boolean: true
|
|
||||||
foo.bar.string: "string"
|
|
||||||
foo.bar.int: 500
|
|
||||||
```
|
|
||||||
|
|
||||||
### Verifying configuration from a file
|
|
||||||
|
|
||||||
When configuration from a file is read, GeckoView logs to `adb logcat`, like:
|
|
||||||
|
|
||||||
```
|
|
||||||
GeckoRuntime I Adding debug configuration from: /data/local/tmp/org.mozilla.geckoview_example-geckoview-config.yaml
|
|
||||||
GeckoDebugConfig D Adding environment variables from debug config: {MOZ_LOG=nsHttp:5}
|
|
||||||
GeckoDebugConfig D Adding arguments from debug config: [--marionette]
|
|
||||||
GeckoDebugConfig D Adding prefs from debug config: {foo.bar.baz=true}
|
|
||||||
```
|
|
||||||
|
|
||||||
When a configuration file is found but cannot be parsed, an error is logged and the file is ignored entirely. When a configuration file is not found, nothing is logged.
|
|
||||||
|
|
||||||
### Controlling configuration from a file
|
|
||||||
|
|
||||||
By default, GeckoView provides a secure web rendering engine. Custom configuration can compromise security in many ways: by storing sensitive data in insecure locations on the device, by trusting websites with incorrect security configurations, by not validating HTTP Public Key Pinning configurations; the list goes on.
|
|
||||||
|
|
||||||
**You should only allow such configuration if your end-user opts-in to the configuration!**
|
|
||||||
|
|
||||||
GeckoView will always read configuration from a file if the consuming Android package is set as the current Android "debug app" (see `set-debug-app` and `clear-debug-app` in the [adb documentation](https://developer.android.com/studio/command-line/adb)). An Android package can be set as the "debug app" without regard to the `android:debuggable` flag. There can only be one "debug app" set at a time. To disable the "debug app" check, [disable reading configuration from a file entirely](#disabling-reading-configuration-from-a-file-entirely). Setting an Android package as the "debug app" requires privileged shell access to the device (generally via `adb shell am ...`, which is only possible on devices which have ADB debugging enabled) and therefore it is safe to act on the "debug app" flag.
|
|
||||||
|
|
||||||
To enable reading configuration from a file:
|
|
||||||
|
|
||||||
```
|
|
||||||
adb shell am set-debug-app --persistent com.yourcompany.yourapp
|
|
||||||
```
|
|
||||||
|
|
||||||
To disable reading configuration from a file:
|
|
||||||
|
|
||||||
```
|
|
||||||
adb shell am clear-debug-app
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Enabling reading configuration from a file unconditionally
|
|
||||||
|
|
||||||
Some applications (for example, web browsers) may want to allow configuration for automation unconditionally, i.e., even when the application is not debuggable, like release builds that have `android:debuggable="false"`. In such cases, you can use [`GeckoRuntimeSettings.Builder#configFilePath`]({{ site.url }}{{ site.baseurl }}/javadoc/mozilla-central/org/mozilla/geckoview/GeckoRuntimeSettings.Builder.html#configFilePath-java.lang.String-) to force GeckoView to read configuration from the given file path, like:
|
|
||||||
|
|
||||||
```java
|
|
||||||
new GeckoRuntimeSettings.Builder()
|
|
||||||
.configFilePath("/your/app/specific/location")
|
|
||||||
.build();
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Disabling reading configuration from a file entirely
|
|
||||||
|
|
||||||
To force GeckoView to never read configuration from a file, even when the embedding application is debuggable, invoke [`GeckoRuntimeSettings.Builder#configFilePath`]({{ site.url }}{{ site.baseurl }}/javadoc/mozilla-central/org/mozilla/geckoview/GeckoRuntimeSettings.Builder.html#configFilePath-java.lang.String-)` with an empty path, like:
|
|
||||||
|
|
||||||
```java
|
|
||||||
new GeckoRuntimeSettings.Builder()
|
|
||||||
.configFilePath("")
|
|
||||||
.build();
|
|
||||||
```
|
|
||||||
|
|
||||||
The empty path is recognized and no file I/O is performed.
|
|
|
@ -1,100 +0,0 @@
|
||||||
---
|
|
||||||
layout: default
|
|
||||||
title: Getting Started with GeckoView
|
|
||||||
nav_order: 2
|
|
||||||
summary: How to use GeckoView in your Android app.
|
|
||||||
tags: [GeckoView,Gecko,mozilla,android,WebView,mobile,mozilla-central,setup,quick start]
|
|
||||||
---
|
|
||||||
|
|
||||||
_Building a browser? Check out [Android Components](https://mozilla-mobile.github.io/android-components/), our collection of ready-to-use support libraries!_
|
|
||||||
|
|
||||||
The following article is a brief guide to embedding GeckoView in an app. For a more in depth tutorial on getting started with GeckoView please read the article we have published on [raywenderlich.com](https://www.raywenderlich.com/1381698-android-tutorial-for-geckoview-getting-started).
|
|
||||||
|
|
||||||
## Table of contents
|
|
||||||
{: .no_toc .text-delta }
|
|
||||||
|
|
||||||
1. TOC
|
|
||||||
{:toc}
|
|
||||||
|
|
||||||
## Configure Gradle
|
|
||||||
|
|
||||||
You need to add or edit four stanzas inside your module's `build.gradle` file.
|
|
||||||
|
|
||||||
**1. Set the GeckoView version**
|
|
||||||
|
|
||||||
_Like Firefox, GeckoView has three release channels: Stable, Beta, and Nightly. Browse the [Maven Repository](https://maven.mozilla.org/?prefix=maven2/org/mozilla/geckoview/) to see currently available builds._
|
|
||||||
|
|
||||||
```groovy
|
|
||||||
ext {
|
|
||||||
geckoviewChannel = "nightly"
|
|
||||||
geckoviewVersion = "70.0.20190712095934"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**2. Add Mozilla's Maven repository**
|
|
||||||
```groovy
|
|
||||||
repositories {
|
|
||||||
maven {
|
|
||||||
url "https://maven.mozilla.org/maven2/"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**3. Java 8 required support**
|
|
||||||
|
|
||||||
As GeckoView uses some Java 8 APIs, it requires these compatibility flags:
|
|
||||||
|
|
||||||
```groovy
|
|
||||||
compileOptions {
|
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
|
||||||
targetCompatibility JavaVersion.VERSION_1_8
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**4. Add GeckoView Implementations**
|
|
||||||
|
|
||||||
```groovy
|
|
||||||
dependencies {
|
|
||||||
// ...
|
|
||||||
implementation "org.mozilla.geckoview:geckoview-${geckoviewChannel}:${geckoviewVersion}"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Add GeckoView to a Layout
|
|
||||||
|
|
||||||
Inside a layout `.xml` file, add the following:
|
|
||||||
|
|
||||||
```xml
|
|
||||||
<org.mozilla.geckoview.GeckoView
|
|
||||||
android:id="@+id/geckoview"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent" />
|
|
||||||
```
|
|
||||||
|
|
||||||
## Initialize GeckoView in an Activity
|
|
||||||
|
|
||||||
**1. Import the GeckoView classes inside an Activity:**
|
|
||||||
|
|
||||||
```java
|
|
||||||
import org.mozilla.geckoview.GeckoRuntime;
|
|
||||||
import org.mozilla.geckoview.GeckoSession;
|
|
||||||
import org.mozilla.geckoview.GeckoView;
|
|
||||||
```
|
|
||||||
|
|
||||||
**2. In that activity's <code>onCreate</code> function, add the following:**
|
|
||||||
|
|
||||||
```java
|
|
||||||
GeckoView view = findViewById(R.id.geckoview);
|
|
||||||
GeckoSession session = new GeckoSession();
|
|
||||||
GeckoRuntime runtime = GeckoRuntime.create(this);
|
|
||||||
|
|
||||||
session.open(runtime);
|
|
||||||
view.setSession(session);
|
|
||||||
session.loadUri("about:buildconfig"); // Or any other URL...
|
|
||||||
```
|
|
||||||
|
|
||||||
## You're done!
|
|
||||||
|
|
||||||
Your application should now load and display a webpage inside of GeckoView.
|
|
||||||
|
|
||||||
To learn more about GeckoView's capabilities, review GeckoView's [JavaDoc](https://mozilla.github.io/geckoview/javadoc/mozilla-central/) or the [reference application](https://searchfox.org/mozilla-central/source/mobile/android/geckoview_example).
|
|
|
@ -1,20 +0,0 @@
|
||||||
---
|
|
||||||
layout: default
|
|
||||||
title: Using GeckoView
|
|
||||||
nav_order: 3
|
|
||||||
---
|
|
||||||
|
|
||||||
# Usage Documentation
|
|
||||||
|
|
||||||
We are working on providing detailed usage documentation for all of GeckoView's most popular features. Here is what we have so far.
|
|
||||||
|
|
||||||
- [GeckoView Quick Start Guide](geckoview-quick-start):
|
|
||||||
Get GeckoView up and running inside your application.
|
|
||||||
- [Interacting with Web Content](web-extensions):
|
|
||||||
Writing Web Extensions, running content scripts and interacting with Javascript running in a web page.
|
|
||||||
- [Working with Site Permissions](permissions):
|
|
||||||
Handling and responding to requests from websites for permissions, such as geolocation, storage, media etc.
|
|
||||||
- [Configuring GeckoView for Automation](automation):
|
|
||||||
Get GeckoView set up on your automation system.
|
|
||||||
|
|
||||||
If there is documentation that you feel is missing, or an existing document doesn't cover the aspect that you are looking for, please request it by raising an issue on our [documentation site](https://github.com/mozilla/geckoview/issues).
|
|
|
@ -1,286 +0,0 @@
|
||||||
---
|
|
||||||
layout: default
|
|
||||||
title: Working with Site Permissions
|
|
||||||
summary: How to receive and respond to permission requests from websites.
|
|
||||||
nav_exclude: true
|
|
||||||
exclude: true
|
|
||||||
tags: [GeckoView,Gecko,mozilla,android,WebView,mobile,permissions,site,media,grant,notifications,storage,persistent storage,app]
|
|
||||||
---
|
|
||||||
# Working with Site Permissions
|
|
||||||
|
|
||||||
When a website wants to access certain services on a user's device, it will send out a permissions request. This document will explain how to use GeckoView to receive those requests, and respond to them by granting or denying those permissions.
|
|
||||||
|
|
||||||
## The Permission Delegate
|
|
||||||
|
|
||||||
The way an app interacts with site permissions in GeckoView is through the [`PermissionDelegate`][1]. There are three broad categories of permission that the `PermissionDelegate` handles, Android Permissions, Content Permissions and Media Permissions. All site permissions handled by GeckoView fall into one of these three categories.
|
|
||||||
|
|
||||||
To get notified about permission requests, you need to implement the `PermissionDelegate` interface:
|
|
||||||
|
|
||||||
```java
|
|
||||||
private class ExamplePermissionDelegate implements GeckoSession.PermissionDelegate {
|
|
||||||
@Override
|
|
||||||
public void onAndroidPermissionsRequest(final GeckoSession session,
|
|
||||||
final String[] permissions,
|
|
||||||
final Callback callback) { }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onContentPermissionRequest(final GeckoSession session,
|
|
||||||
final String uri,
|
|
||||||
final int type, final Callback callback) { }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onMediaPermissionRequest(final GeckoSession session,
|
|
||||||
final String uri,
|
|
||||||
final MediaSource[] video,
|
|
||||||
final MediaSource[] audio,
|
|
||||||
final MediaCallback callback) { }
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
You will then need to register the delegate with your [`GeckoSession`][3] instance.
|
|
||||||
|
|
||||||
```java
|
|
||||||
public class GeckoViewActivity extends AppCompatActivity {
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
final ExamplePermissionDelegate permission = new ExamplePermissionDelegate();
|
|
||||||
session.setPermissionDelegate(permission);
|
|
||||||
|
|
||||||
...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Android Permissions
|
|
||||||
|
|
||||||
Android permissions are requested whenever a site wants access to a device's navigation or input capabilites.
|
|
||||||
|
|
||||||
The user will often need to grant these Android permissions to the app alongside granting the Content or Media site permissions.
|
|
||||||
|
|
||||||
When you receive an [`onAndroidPermissionsRequest`][2] call, you will also receive the `GeckoSession` the request was sent from, an array containing the permissions that are being requested, and a [`Callback`][4] to respond to the request. It is then up to the app to request those permissions from the device, which can be done using [`requestPermissions`][5].
|
|
||||||
|
|
||||||
Possible `permissions` values are; [`ACCESS_COARSE_LOCATION`][6], [`ACCESS_FINE_LOCATION`][7], [`CAMERA`][8] or [`RECORD_AUDIO`][9].
|
|
||||||
|
|
||||||
```java
|
|
||||||
private class ExamplePermissionDelegate implements GeckoSession.PermissionDelegate {
|
|
||||||
private Callback mCallback;
|
|
||||||
|
|
||||||
public void onRequestPermissionsResult(final String[] permissions,
|
|
||||||
final int[] grantResults) {
|
|
||||||
if (mCallback == null) { return; }
|
|
||||||
|
|
||||||
final Callback cb = mCallback;
|
|
||||||
mCallback = null;
|
|
||||||
for (final int result : grantResults) {
|
|
||||||
if (result != PackageManager.PERMISSION_GRANTED) {
|
|
||||||
// At least one permission was not granted.
|
|
||||||
cb.reject();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cb.grant();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAndroidPermissionsRequest(final GeckoSession session,
|
|
||||||
final String[] permissions,
|
|
||||||
final Callback callback) {
|
|
||||||
mCallback = callback;
|
|
||||||
requestPermissions(permissions, androidPermissionRequestCode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class GeckoViewActivity extends AppCompatActivity {
|
|
||||||
@Override
|
|
||||||
public void onRequestPermissionsResult(final int requestCode,
|
|
||||||
final String[] permissions,
|
|
||||||
final int[] grantResults) {
|
|
||||||
if (requestCode == REQUEST_PERMISSIONS ||
|
|
||||||
requestCode == REQUEST_WRITE_EXTERNAL_STORAGE) {
|
|
||||||
final ExamplePermissionDelegate permission = (ExamplePermissionDelegate)
|
|
||||||
getCurrentSession().getPermissionDelegate();
|
|
||||||
permission.onRequestPermissionsResult(permissions, grantResults);
|
|
||||||
} else {
|
|
||||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Content Permissions
|
|
||||||
|
|
||||||
Content permissions are requested whenever a site wants access to content that is stored on the device. The content permissions that can be requested through GeckoView are; [`Geolocation`][10], [`Site Notifications`][11] and [`Persistent Storage`][12] access.
|
|
||||||
|
|
||||||
When you receive an [`onContentPermissionRequest`][13] call, you will also receive the `GeckoSession` the request was sent from, the URI of the site that requested the permission, as a String, the type of the content permission requested (geolocation, site notification or persistent storage), and a [`Callback`][4] to respond to the request. It is then up to the app to present UI to the user asking for the permissions, and to notify GeckoView of the response via the `Callback`.
|
|
||||||
|
|
||||||
*Please note, in the case of `PERMISSION_DESKTOP_NOTIFICATION` and `PERMISSION_PERSISTENT_STORAGE`, GeckoView does not track accepted permissions and prevent further requests being sent for a particular site. It is therefore up to the calling app to do this if that is the desired behaviour. The code below demonstrates how to track storage permissions by site and track notification permission rejection for the whole app*
|
|
||||||
|
|
||||||
```java
|
|
||||||
private class ExamplePermissionDelegate implements GeckoSession.PermissionDelegate {
|
|
||||||
private boolean showNotificationsRejected;
|
|
||||||
private ArrayList<String> acceptedPersistentStorage = new ArrayList<String>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onContentPermissionRequest(final GeckoSession session,
|
|
||||||
final String uri,
|
|
||||||
final int type,
|
|
||||||
final Callback callback) {
|
|
||||||
final int resId;
|
|
||||||
Callback contentPermissionCallback = callback;
|
|
||||||
if (PERMISSION_GEOLOCATION == type) {
|
|
||||||
resId = R.string.request_geolocation;
|
|
||||||
} else if (PERMISSION_DESKTOP_NOTIFICATION == type) {
|
|
||||||
if (showNotificationsRejected) {
|
|
||||||
callback.reject();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
resId = R.string.request_notification;
|
|
||||||
} else if (PERMISSION_PERSISTENT_STORAGE == type) {
|
|
||||||
if (acceptedPersistentStorage.contains(uri)) {
|
|
||||||
callback.grant();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
resId = R.string.request_storage;
|
|
||||||
} else { // unknown permission type
|
|
||||||
callback.reject();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final String title = getString(resId, Uri.parse(uri).getAuthority());
|
|
||||||
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
|
||||||
builder.setTitle(title)
|
|
||||||
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(final DialogInterface dialog, final int which) {
|
|
||||||
if (PERMISSION_DESKTOP_NOTIFICATION == type) {
|
|
||||||
showNotificationsRejected = false;
|
|
||||||
}
|
|
||||||
callback.reject();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(final DialogInterface dialog, final int which) {
|
|
||||||
if (PERMISSION_PERSISTENT_STORAGE == type) {
|
|
||||||
acceptedPersistentStorage.add(mUri);
|
|
||||||
} else if (PERMISSION_DESKTOP_NOTIFICATION == type) {
|
|
||||||
showNotificationsRejected = true;
|
|
||||||
}
|
|
||||||
callback.grant();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
final AlertDialog dialog = builder.create();
|
|
||||||
dialog.show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Media Permissions
|
|
||||||
Media permissions are requested whenever a site wants access to play or record media from the device's camera and microphone.
|
|
||||||
|
|
||||||
When you receive an [`onMediaPermissionRequest`][14] call, you will also receive the `GeckoSession` the request was sent from, the URI of the site that requested the permission, as a String, the list of video devices available, if requesting video, the list of audio devices available, if requesting audio, and a [`MediaCallback`][15] to respond to the request.
|
|
||||||
|
|
||||||
It is up to the app to present UI to the user asking for the permissions, and to notify GeckoView of the response via the `MediaCallback`.
|
|
||||||
|
|
||||||
*Please note, media permissions will still be requested if the associated device permissions have been denied if there are video or audio sources in that category that can still be accessed when listed. It is the responsibility of consumers to ensure that media permission requests are not displayed in this case.*
|
|
||||||
|
|
||||||
```java
|
|
||||||
private class ExamplePermissionDelegate implements GeckoSession.PermissionDelegate {
|
|
||||||
@Override
|
|
||||||
public void onMediaPermissionRequest(final GeckoSession session,
|
|
||||||
final String uri,
|
|
||||||
final MediaSource[] video,
|
|
||||||
final MediaSource[] audio,
|
|
||||||
final MediaCallback callback) {
|
|
||||||
// Reject permission if Android permission has been previously denied.
|
|
||||||
if ((audio != null
|
|
||||||
&& ContextCompat.checkSelfPermission(GeckoViewActivity.this,
|
|
||||||
Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED)
|
|
||||||
|| (video != null
|
|
||||||
&& ContextCompat.checkSelfPermission(GeckoViewActivity.this,
|
|
||||||
Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED)) {
|
|
||||||
callback.reject();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final String host = Uri.parse(uri).getAuthority();
|
|
||||||
final String title;
|
|
||||||
if (audio == null) {
|
|
||||||
title = getString(R.string.request_video, host);
|
|
||||||
} else if (video == null) {
|
|
||||||
title = getString(R.string.request_audio, host);
|
|
||||||
} else {
|
|
||||||
title = getString(R.string.request_media, host);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the media device name from the `MediaDevice`
|
|
||||||
String[] videoNames = normalizeMediaName(video);
|
|
||||||
String[] audioNames = normalizeMediaName(audio);
|
|
||||||
|
|
||||||
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
|
||||||
|
|
||||||
// Create drop down boxes to allow users to select which device to grant permission to
|
|
||||||
final LinearLayout container = addStandardLayout(builder, title, null);
|
|
||||||
final Spinner videoSpinner;
|
|
||||||
if (video != null) {
|
|
||||||
videoSpinner = addMediaSpinner(builder.getContext(), container, video, videoNames); // create spinner and add to alert UI
|
|
||||||
} else {
|
|
||||||
videoSpinner = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Spinner audioSpinner;
|
|
||||||
if (audio != null) {
|
|
||||||
audioSpinner = addMediaSpinner(builder.getContext(), container, audio, audioNames); // create spinner and add to alert UI
|
|
||||||
} else {
|
|
||||||
audioSpinner = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.setNegativeButton(android.R.string.cancel, null)
|
|
||||||
.setPositiveButton(android.R.string.ok,
|
|
||||||
new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(final DialogInterface dialog, final int which) {
|
|
||||||
// gather selected media devices and grant access
|
|
||||||
final MediaSource video = (videoSpinner != null)
|
|
||||||
? (MediaSource) videoSpinner.getSelectedItem() : null;
|
|
||||||
final MediaSource audio = (audioSpinner != null)
|
|
||||||
? (MediaSource) audioSpinner.getSelectedItem() : null;
|
|
||||||
callback.grant(video, audio);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
final AlertDialog dialog = builder.create();
|
|
||||||
dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
|
|
||||||
@Override
|
|
||||||
public void onDismiss(final DialogInterface dialog) {
|
|
||||||
callback.reject();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
dialog.show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
To see the `PermissionsDelegate` in action, you can find the full example implementation in the [GeckoView example app][16].
|
|
||||||
|
|
||||||
[1]: {{ site.url }}{{ site.baseurl }}/javadoc/mozilla-central/org/mozilla/geckoview/GeckoSession.PermissionDelegate.html
|
|
||||||
[2]: {{ site.url }}{{ site.baseurl }}/javadoc/mozilla-central/org/mozilla/geckoview/GeckoSession.PermissionDelegate.html#onAndroidPermissionsRequest-org.mozilla.geckoview.GeckoSession-java.lang.String:A-org.mozilla.geckoview.GeckoSession.PermissionDelegate.Callback-
|
|
||||||
[3]: {{ site.url }}{{ site.baseurl }}/javadoc/mozilla-central/org/mozilla/geckoview/GeckoSession.html
|
|
||||||
[4]: {{ site.url }}{{ site.baseurl }}/javadoc/mozilla-central/org/mozilla/geckoview/GeckoSession.PermissionDelegate.Callback.html
|
|
||||||
[5]: https://developer.android.com/reference/android/app/Activity#requestPermissions(java.lang.String%5B%5D,%2520int)
|
|
||||||
[6]: https://developer.android.com/reference/android/Manifest.permission.html#ACCESS_COARSE_LOCATION
|
|
||||||
[7]: https://developer.android.com/reference/android/Manifest.permission.html#ACCESS_FINE_LOCATION
|
|
||||||
[8]: https://developer.android.com/reference/android/Manifest.permission.html#CAMERA
|
|
||||||
[9]: https://developer.android.com/reference/android/Manifest.permission.html#RECORD_AUDIO
|
|
||||||
[10]: {{ site.url }}{{ site.baseurl }}/javadoc/mozilla-central/org/mozilla/geckoview/GeckoSession.PermissionDelegate.html#PERMISSION_GEOLOCATION
|
|
||||||
[11]: {{ site.url }}{{ site.baseurl }}/javadoc/mozilla-central/org/mozilla/geckoview/GeckoSession.PermissionDelegate.html#PERMISSION_DESKTOP_NOTIFICATION
|
|
||||||
[12]: {{ site.url }}{{ site.baseurl }}/javadoc/mozilla-central/org/mozilla/geckoview/GeckoSession.PermissionDelegate.html#PERMISSION_PERSISTENT_STORAGE
|
|
||||||
[13]: {{ site.url }}{{ site.baseurl }}/javadoc/mozilla-central/org/mozilla/geckoview/GeckoSession.PermissionDelegate.html#onContentPermissionRequest-org.mozilla.geckoview.GeckoSession-java.lang.String-int-org.mozilla.geckoview.GeckoSession.PermissionDelegate.Callback-
|
|
||||||
[14]: {{ site.url }}{{ site.baseurl }}/javadoc/mozilla-central/org/mozilla/geckoview/GeckoSession.PermissionDelegate.html#onMediaPermissionRequest-org.mozilla.geckoview.GeckoSession-java.lang.String-org.mozilla.geckoview.GeckoSession.PermissionDelegate.MediaSource:A-org.mozilla.geckoview.GeckoSession.PermissionDelegate.MediaSource:A-org.mozilla.geckoview.GeckoSession.PermissionDelegate.MediaCallback-
|
|
||||||
[15]: {{ site.url }}{{ site.baseurl }}/javadoc/mozilla-central/org/mozilla/geckoview/GeckoSession.PermissionDelegate.MediaCallback.html
|
|
||||||
[16]: https://searchfox.org/mozilla-central/source/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/GeckoViewActivity.java#686
|
|
|
@ -1,330 +0,0 @@
|
||||||
---
|
|
||||||
layout: default
|
|
||||||
title: Interacting with Web content
|
|
||||||
summary: How to interact with Web content and register WebExtensions in GeckoView.
|
|
||||||
nav_exclude: true
|
|
||||||
exclude: true
|
|
||||||
---
|
|
||||||
# Interacting with Web content and WebExtensions
|
|
||||||
|
|
||||||
GeckoView allows embedder applications to register and run [WebExtensions][8]
|
|
||||||
in a GeckoView instance. WebExtensions are the preferred way to interact with
|
|
||||||
Web content.
|
|
||||||
|
|
||||||
## Running WebExtensions in GeckoView
|
|
||||||
|
|
||||||
WebExtensions bundled with applications can be provided either in compressed
|
|
||||||
`.xpi` files or in regular folders. Like ordinary WebExtensions, every
|
|
||||||
WebExtension requires a [`manifest.json`][23] file.
|
|
||||||
|
|
||||||
To run a WebExtension in GeckoView, simply create a [`WebExtension`][3] object
|
|
||||||
and register it in your [`GeckoRuntime`][24] instance.
|
|
||||||
|
|
||||||
```java
|
|
||||||
WebExtension extension = new WebExtension(
|
|
||||||
// The location where the web extension is installed, if the location is a
|
|
||||||
// folder make sure the path ends with a "/" character.
|
|
||||||
"resource://android/assets/messaging/",
|
|
||||||
// This is the id and must be unique for every web extension
|
|
||||||
"myextension@example.com",
|
|
||||||
// Extra flags can be specified here
|
|
||||||
WebExtension.Flags.NONE);
|
|
||||||
|
|
||||||
// Run the WebExtension
|
|
||||||
runtime.registerWebExtension(extension);
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that the lifetime of the WebExtension is tied with the lifetime of the
|
|
||||||
[`GeckoRuntime`][24] instance. The WebExtension will need to be registered
|
|
||||||
every time the runtime is created and will not persist once the runtime is
|
|
||||||
closed.
|
|
||||||
|
|
||||||
To locate files bundled with the APK, GeckoView provides a shorthand
|
|
||||||
`resource://android/` that points to the root of the APK.
|
|
||||||
|
|
||||||
E.g. `resource://android/assets/messaging/` will point to the
|
|
||||||
`/assets/messaging/` folder present in the APK.
|
|
||||||
|
|
||||||
## Communicating with Web Content
|
|
||||||
GeckoView allows bidirectional communication with Web pages through
|
|
||||||
WebExtensions.
|
|
||||||
|
|
||||||
When using GeckoView, [native messaging][11] can be used for communicating to
|
|
||||||
and from the browser.
|
|
||||||
* [`runtime.sendNativeMessage`][12] for one-off messages.
|
|
||||||
* [`runtime.connectNative`][13] for connection-based messaging.
|
|
||||||
|
|
||||||
Note: these APIs are only available when the `geckoViewAddons` [permission][17]
|
|
||||||
is present in the `manifest.json` file of the WebExtension.
|
|
||||||
|
|
||||||
### One-off messages
|
|
||||||
|
|
||||||
The easiest way to send messages from a [content script][9] or a [background
|
|
||||||
script][10] is using [`runtime.sendNativeMessage`][12]. The app will set up a
|
|
||||||
message delegate on the same `nativeApp` that the WebExtension is using to send
|
|
||||||
messages. In our example we will use the `"browser"` native app identifier.
|
|
||||||
|
|
||||||
To receive messages from the background script, call [`setMessageDelegate`][14]
|
|
||||||
on the [`WebExtension`][3] object.
|
|
||||||
|
|
||||||
[`GeckoSession.setMessageDelegate`][16] allows the app to receive messages from
|
|
||||||
content scripts.
|
|
||||||
|
|
||||||
Note: WebExtensions can only send messages from content scripts if explicitly
|
|
||||||
authorized by the app setting
|
|
||||||
[`WebExtension.Flags.ALLOW_CONTENT_MESSAGING`][22] in the [constructor][15].
|
|
||||||
|
|
||||||
### Example
|
|
||||||
|
|
||||||
Let's set up an activity that registers a WebExtension located in the
|
|
||||||
`/assets/messaging/` folder of the APK. This activity will set up a
|
|
||||||
[`MessageDelegate`][18] that will be used to communicate with Web Content.
|
|
||||||
|
|
||||||
You can find the full example here: [MessagingExample][20].
|
|
||||||
|
|
||||||
##### Activity.java
|
|
||||||
```java
|
|
||||||
WebExtension.MessageDelegate messageDelegate = new WebExtension.MessageDelegate() {
|
|
||||||
@Nullable
|
|
||||||
public GeckoResult<Object> onMessage(final @NonNull Object message,
|
|
||||||
final @NonNull WebExtension.MessageSender sender) {
|
|
||||||
// The sender object contains information about the session that
|
|
||||||
// originated this message and can be used to validate that the message
|
|
||||||
// has been sent from the expected location.
|
|
||||||
|
|
||||||
// Be careful when handling the type of message as it depends on what
|
|
||||||
// type of object was sent from the WebExtension script.
|
|
||||||
if (message instanceof JSONObject) {
|
|
||||||
// Do something with message
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
WebExtension extension = new WebExtension(
|
|
||||||
"resource://android/assets/messaging/",
|
|
||||||
"myextension@example.com",
|
|
||||||
WebExtension.Flags.ALLOW_CONTENT_MESSAGING);
|
|
||||||
|
|
||||||
// Run the WebExtension
|
|
||||||
runtime.registerWebExtension(extension);
|
|
||||||
|
|
||||||
// Set the delegate that will receive messages coming from this WebExtension.
|
|
||||||
session.setMessageDelegate(messageDelegate, "browser");
|
|
||||||
```
|
|
||||||
|
|
||||||
Now add the `geckoViewAddons` and `nativeMessaging` permissions to your
|
|
||||||
`manifest.json` file.
|
|
||||||
|
|
||||||
##### /assets/messaging/manifest.json
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"manifest_version": 2,
|
|
||||||
"name": "messaging",
|
|
||||||
"version": "1.0",
|
|
||||||
"description": "Example messaging web extension.",
|
|
||||||
"content_scripts": [
|
|
||||||
{
|
|
||||||
"matches": ["*://*.twitter.com/*"],
|
|
||||||
"js": ["messaging.js"]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"permissions": [
|
|
||||||
"nativeMessaging",
|
|
||||||
"geckoViewAddons"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
And finally, write a content script that will send a message to the app when a
|
|
||||||
certain event occurs. For example, you could send a message whenever a [WPA
|
|
||||||
manifest][19] is found on the page. Note that our `nativeApp` identifier used
|
|
||||||
for `sendNativeMessage` is the same as the one used in the `setMessageDelegate`
|
|
||||||
call in [`Activity.java`](#activityjava).
|
|
||||||
|
|
||||||
##### /assets/messaging/messaging.js
|
|
||||||
```javascript
|
|
||||||
let manifest = document.querySelector("head > link[rel=manifest]");
|
|
||||||
if (manifest) {
|
|
||||||
fetch(manifest.href)
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(json => {
|
|
||||||
let message = {type: "WPAManifest", manifest: json};
|
|
||||||
browser.runtime.sendNativeMessage("browser", message);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
You can handle this message in the `onMessage` method in the `messageDelegate`
|
|
||||||
[above](#activityjava).
|
|
||||||
|
|
||||||
```java
|
|
||||||
@Nullable
|
|
||||||
public GeckoResult<Object> onMessage(final @NonNull Object message,
|
|
||||||
final @NonNull WebExtension.MessageSender sender) {
|
|
||||||
if (message instanceof JSONObject) {
|
|
||||||
JSONObject json = (JSONObject) message;
|
|
||||||
try {
|
|
||||||
if (json.has("type") && "WPAManifest".equals(json.getString("type"))) {
|
|
||||||
JSONObject manifest = json.getJSONObject("manifest");
|
|
||||||
Log.d("MessageDelegate", "Found WPA manifest: " + manifest);
|
|
||||||
}
|
|
||||||
} catch (JSONException ex) {
|
|
||||||
Log.e("MessageDelegate", "Invalid manifest", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that, in the case of content scripts, `sender.session` will be a reference
|
|
||||||
to the `GeckoSession` instance from which the message originated. For
|
|
||||||
background scripts, `sender.session` will always be `null`.
|
|
||||||
|
|
||||||
Also note that the type of `message` will depend on what was sent from the
|
|
||||||
WebExtension.
|
|
||||||
|
|
||||||
The type of `message` will be `JSONObject` when the WebExtension sends a
|
|
||||||
javascript object, but could also be a primitive type if the WebExtension sends
|
|
||||||
one, e.g. for
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
runtime.browser.sendNativeMessage("browser", "Hello World!");
|
|
||||||
```
|
|
||||||
|
|
||||||
the type of `message` will be `java.util.String`.
|
|
||||||
|
|
||||||
## Connection-based messaging
|
|
||||||
|
|
||||||
For more complex scenarios or for when you want to send messages _from_ the app
|
|
||||||
to the WebExtension, [`runtime.connectNative`][13] is the appropriate API to
|
|
||||||
use.
|
|
||||||
|
|
||||||
`connectNative` returns a [`runtime.Port`][6] that can be used to send messages
|
|
||||||
to the app. On the app side, implementing [`MessageDelegate#onConnect`][1] will
|
|
||||||
allow you to receive a [`Port`][7] object that can be used to receive and send
|
|
||||||
messages to the WebExtension.
|
|
||||||
|
|
||||||
The following example can be found [here][21].
|
|
||||||
|
|
||||||
For this example, the WebExtension side will do the following:
|
|
||||||
* open a port on the background script using `connectNative`
|
|
||||||
* listen on the port and log to console every message received
|
|
||||||
* send a message immediately after opening the port.
|
|
||||||
|
|
||||||
##### /assets/messaging/background.js
|
|
||||||
```javascript
|
|
||||||
// Establish connection with app
|
|
||||||
let port = browser.runtime.connectNative("browser");
|
|
||||||
port.onMessage.addListener(response => {
|
|
||||||
// Let's just echo the message back
|
|
||||||
port.postMessage(`Received: ${JSON.stringify(response)}`);
|
|
||||||
});
|
|
||||||
port.postMessage("Hello from WebExtension!");
|
|
||||||
```
|
|
||||||
|
|
||||||
On the app side, following the [above](#activityjava) example, `onConnect` will
|
|
||||||
be storing the `Port` object in a member variable and then using it when
|
|
||||||
needed.
|
|
||||||
|
|
||||||
```java
|
|
||||||
private WebExtension.Port mPort;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
// ... initialize GeckoView
|
|
||||||
|
|
||||||
// This delegate will handle all communications from and to a specific Port
|
|
||||||
// object
|
|
||||||
WebExtension.PortDelegate portDelegate = new WebExtension.PortDelegate() {
|
|
||||||
public WebExtension.Port port = null;
|
|
||||||
|
|
||||||
public void onPortMessage(final @NonNull Object message,
|
|
||||||
final @NonNull WebExtension.Port port) {
|
|
||||||
// This method will be called every time a message is sent from the
|
|
||||||
// WebExtension through this port. For now, let's just log a
|
|
||||||
// message.
|
|
||||||
Log.d("PortDelegate", "Received message from WebExtension: "
|
|
||||||
+ message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onDisconnect(final @NonNull WebExtension.Port port) {
|
|
||||||
// After this method is called, this port is not usable anymore.
|
|
||||||
if (port == mPort) {
|
|
||||||
mPort = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// This delegate will handle requests to open a port coming from the
|
|
||||||
// WebExtension
|
|
||||||
WebExtension.MessageDelegate messageDelegate = new WebExtension.MessageDelegate() {
|
|
||||||
@Nullable
|
|
||||||
public void onConnect(final @NonNull WebExtension.Port port) {
|
|
||||||
// Let's store the Port object in a member variable so it can be
|
|
||||||
// used later to exchange messages with the WebExtension.
|
|
||||||
mPort = port;
|
|
||||||
|
|
||||||
// Registering the delegate will allow us to receive messages sent
|
|
||||||
// through this port.
|
|
||||||
mPort.setDelegate(portDelegate);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
WebExtension extension = new WebExtension(
|
|
||||||
"resource://android/assets/messaging/");
|
|
||||||
|
|
||||||
// Register message delegate for the background script
|
|
||||||
extension.setMessageDelegate(messageDelegate, "browser");
|
|
||||||
|
|
||||||
// ... other
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
For example, let's send a message to the WebExtension every time the user long
|
|
||||||
presses on a key on the virtual keyboard, e.g. on the back button.
|
|
||||||
|
|
||||||
```java
|
|
||||||
@Override
|
|
||||||
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
|
|
||||||
if (mPort == null) {
|
|
||||||
// No WebExtension registered yet, let's ignore this message
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSONObject message = new JSONObject();
|
|
||||||
try {
|
|
||||||
message.put("keyCode", keyCode);
|
|
||||||
message.put("event", KeyEvent.keyCodeToString(event.getKeyCode()));
|
|
||||||
} catch (JSONException ex) {
|
|
||||||
throw new RuntimeException(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
mPort.postMessage(message);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
This allows bidirectional communication between the app and the WebExtension.
|
|
||||||
|
|
||||||
[1]: {{ site.url }}{{ site.baseurl }}/javadoc/mozilla-central/org/mozilla/geckoview/WebExtension.MessageDelegate.html#onConnect-org.mozilla.geckoview.WebExtension.Port-
|
|
||||||
[3]: {{ site.url }}{{ site.baseurl }}/javadoc/mozilla-central/org/mozilla/geckoview/WebExtension.html
|
|
||||||
[6]: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/Port
|
|
||||||
[7]: {{ site.url }}{{ site.baseurl }}/javadoc/mozilla-central/org/mozilla/geckoview/WebExtension.Port.html
|
|
||||||
[8]: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions
|
|
||||||
[9]: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_scripts
|
|
||||||
[10]: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Anatomy_of_a_WebExtension#Background_scripts
|
|
||||||
[11]: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_messaging#Exchanging_messages
|
|
||||||
[12]: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/sendNativeMessage
|
|
||||||
[13]: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/connectNative
|
|
||||||
[14]: {{ site.url }}{{ site.baseurl }}/javadoc/mozilla-central/org/mozilla/geckoview/WebExtension.html#setMessageDelegate-org.mozilla.geckoview.WebExtension.MessageDelegate-java.lang.String-
|
|
||||||
[15]: {{ site.url }}{{ site.baseurl }}/javadoc/mozilla-central/org/mozilla/geckoview/WebExtension.html#WebExtension-java.lang.String-java.lang.String-long-
|
|
||||||
[16]: ../javadoc/mozilla-central/org/mozilla/geckoview/GeckoSession.html#setMessageDelegate-org.mozilla.geckoview.WebExtension.MessageDelegate-java.lang.String-
|
|
||||||
[17]: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/permissions
|
|
||||||
[18]: {{ site.url }}{{ site.baseurl }}/javadoc/mozilla-central/org/mozilla/geckoview/WebExtension.MessageDelegate.html
|
|
||||||
[19]: https://developer.mozilla.org/en-US/docs/Web/Manifest
|
|
||||||
[20]: https://github.com/mozilla/geckoview/tree/gh-pages/examples/extensions/MessagingExample/
|
|
||||||
[21]: https://github.com/mozilla/geckoview/tree/gh-pages/examples/extensions/PortMessagingExample/
|
|
||||||
[22]: {{ site.url }}{{ site.baseurl }}/javadoc/mozilla-central/org/mozilla/geckoview/WebExtension.Flags.html#ALLOW_CONTENT_MESSAGING
|
|
||||||
[23]: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json
|
|
||||||
[24]: {{ site.url }}{{ site.baseurl }}/javadoc/mozilla-central/org/mozilla/geckoview/GeckoRuntime.html
|
|
|
@ -1,149 +0,0 @@
|
||||||
---
|
|
||||||
layout: default
|
|
||||||
title: Mozilla Central Contributor Guide
|
|
||||||
summary: Guide to setting up as a contributor to mozilla-central.
|
|
||||||
tags: [GeckoView,Gecko,mozilla,android,WebView,mobile,mozilla-central,bug fix,submit,patch,arcanist,arc,moz-phab,phabricator]
|
|
||||||
nav_exclude: true
|
|
||||||
exclude: true
|
|
||||||
---
|
|
||||||
## Table of contents
|
|
||||||
{: .no_toc .text-delta }
|
|
||||||
|
|
||||||
1. TOC
|
|
||||||
{:toc}
|
|
||||||
|
|
||||||
# Submitting a patch to Firefox using Git.
|
|
||||||
|
|
||||||
This guide will take you through submitting and updating a patch to `mozilla-central` as a git user. You need to already be [set up to use git to contribute to `mozilla-central`](mc-quick-start).
|
|
||||||
|
|
||||||
## Performing a bug fix
|
|
||||||
|
|
||||||
All of the open bugs for issues in Firefox can be found in [Bugzilla](https://bugzilla.mozilla.org). If you know the component that you wish to contribute to you can use Bugzilla to search for issues in that project. If you are unsure which component you are interested in, you can search the [Good First Bugs](https://bugzilla.mozilla.org/buglist.cgi?quicksearch=good-first-bug) list to find something you want to work on.
|
|
||||||
|
|
||||||
* Once you have your bug, assign it to yourself in Bugzilla.
|
|
||||||
* Update your local copy of the firefox codebase to match the current version on the servers to ensure you are working with the most up to date code.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git remote update
|
|
||||||
```
|
|
||||||
* Create a new feature branch tracking either Central or Inbound.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git checkout -b bugxxxxxxx [inbound|central]/default
|
|
||||||
```
|
|
||||||
* Work on your bug, checking into git according to your preferred workflow. _Try to ensure that each individual commit compiles and passes all of the tests for your component. This will make it easier to land if you use `moz-phab` to submit (details later in this post)._
|
|
||||||
|
|
||||||
It may be helpful to have Mozilla commit access, at least level 1. There are three levels of commit access that give increasing levels of access to the repositories.
|
|
||||||
|
|
||||||
Level 1: Try/User access. You will need this level of access commit to the try server.
|
|
||||||
Level 2: General access. This will give you full commit access to any mercurial or SVN repository not requiring level 3 access.
|
|
||||||
Level 3: Core access. You will need this level to commit directly to any of the core repositories (Firefox/Thunderbird/Fennec).
|
|
||||||
|
|
||||||
If you wish to apply for commit access, please follow the guide found in the [Mozilla Commit Access Policy](https://www.mozilla.org/en-US/about/governance/policies/commit/access-policy/).
|
|
||||||
|
|
||||||
### Submitting a patch that touches C/C++
|
|
||||||
|
|
||||||
If your patch makes changes to any C or C++ code and your editor does not have `clang-format` support, you should run the clang-format linter before submitting your patch to ensure that your code is properly formatted.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
mach clang-format -p path/to/file.cpp
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that `./mach bootstrap` will offer to set up a commit hook that will automatically do this for you.
|
|
||||||
|
|
||||||
### Submitting to `try` with Level 1 commit access.
|
|
||||||
|
|
||||||
If you only have Level 1 access, you will still need to submit your patch through phabricator, but you can test it on the try server first.
|
|
||||||
|
|
||||||
* Use `./mach try fuzzy` to select jobs to run and push to try.
|
|
||||||
|
|
||||||
### Submitting a patch via Phabricator.
|
|
||||||
|
|
||||||
To commit anything to the repository, you will need to set up Arcanist and Phabricator. If you are using `git-cinnabar` then you will need to use git enabled versions of these tools.
|
|
||||||
|
|
||||||
#### Install Arcanist (Github version)
|
|
||||||
|
|
||||||
* Ensure PHP is installed
|
|
||||||
* [Install Arcanist](https://secure.phabricator.com/book/phabricator/article/arcanist_quick_start/)
|
|
||||||
|
|
||||||
#### Set up Phabricator
|
|
||||||
|
|
||||||
* In a browser, visit Mozilla's Phabricator instance at https://phabricator.services.mozilla.com/.
|
|
||||||
* Click "Log In" at the top of the page
|
|
||||||
|
|
||||||
![alt text]({{ site.url }}/assets/LogInPhab.png "Log in to Phabricator")
|
|
||||||
* Click the "Log In or Register" button on the next page. This will take you to Bugzilla to log in or register a new account.
|
|
||||||
|
|
||||||
![alt text]({{ site.url }}/assets/LogInOrRegister.png "Log in or register a Phabiricator account")
|
|
||||||
* Sign in with your Bugzilla credentials, or create a new account.
|
|
||||||
|
|
||||||
![alt text]({{ site.url }}/assets/LogInBugzilla.png "Log in with Bugzilla")
|
|
||||||
* You will be redirected back to Phabricator, where you will have to create a new Phabricator account.
|
|
||||||
<Screenshot Needed>
|
|
||||||
* Fill in/amend any fields on the form and click "Register Account".
|
|
||||||
<Screenshot Needed>
|
|
||||||
* You now have a Phabricator account and can submit and review patches.
|
|
||||||
|
|
||||||
#### Using Arcanist to submit a patch
|
|
||||||
|
|
||||||
* Ensure you are on the branch where you have commits that you want to submit.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git checkout "your-branch-with-commits"
|
|
||||||
```
|
|
||||||
* Create a differential patch containing your commits
|
|
||||||
|
|
||||||
```bash
|
|
||||||
arc diff
|
|
||||||
```
|
|
||||||
|
|
||||||
* If you have any uncommited files, Arcanist will ask if you want to commit them.
|
|
||||||
* If you have any files in the path not added to git Arcanist will ask if you want to ignore them.
|
|
||||||
* After formatting your patch, Arcanist will open a nano/emacs file for you to enter the commit details. If you have many individual git commits in your arcanist diff then the first line of the first commit message will become the patch title, and the rest of the commit, plus the messages for the other commits in the patch will form the summary.
|
|
||||||
* Ensure you have entered the bug number against the `Bug #` field.
|
|
||||||
* If you know who you want to review your patch, put their Phabricator handle against the `reviewers` field. If in doubt, look to see who filed, or is listed as a mentor on, the bug you are addressing and choose them.
|
|
||||||
* Close the editor (Ctrl X) to save the patch.
|
|
||||||
* Arcanist now formats your patch and submits it to Phabricator. It will display the Phabricator link in the output.
|
|
||||||
* Copy that link and paste it into a browser window to view your patch.
|
|
||||||
|
|
||||||
You may have noticed when using Arcanist that it wraps all of your carefully curated Github commits into a single patch. If you have made many commits that are self contained and pass all the tests then you may wish to submit a patch for each commit. This will make it easier to review. The way to do this is via `moz-phab`. `moz-phab` required Arcanist so you do have to have that installed first.
|
|
||||||
|
|
||||||
#### Installing `moz-phab`
|
|
||||||
|
|
||||||
|
|
||||||
N.B. If each individual patch does not compile and pass tests you will not be able to land each patch individually. In this case, please use Arcanist.
|
|
||||||
|
|
||||||
* Download the latest version of [`moz-phab`](https://github.com/mozilla-conduit/review/releases/tags) from the repository.
|
|
||||||
* Add it to your path
|
|
||||||
|
|
||||||
```bash
|
|
||||||
export PATH="$PATH:/somewhere/moz-phab/bin/"
|
|
||||||
echo PATH="$PATH:/somewhere/moz-phab/bin/" >> ~/.bash_profile
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Submitting a patch using `moz-phab`.
|
|
||||||
|
|
||||||
* Ensure you are on the branch where you have commits that you want to submit.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git checkout your-branch
|
|
||||||
```
|
|
||||||
* Check the revision numbers for the commits you want to submit
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git log
|
|
||||||
```
|
|
||||||
* Run `moz-phab`. Specifying a start commit will submit all commits from that commit. Specifying an end commit will submit all commits up to that commit. If no positional arguments are provided, the range is determined to be starting with the first non-public, non-obsolete changeset (for Mercurial) and ending with the currently checked-out changeset.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
moz-phab submit [start_rev] [end_rev]
|
|
||||||
```
|
|
||||||
* You will recieve a Phabricator link for each commit in the set.
|
|
||||||
|
|
||||||
### Updating a patch
|
|
||||||
|
|
||||||
* Often you will need to make amendments to a patch after it has been submitted to address review comments. To do this, add your commits to the base branch of your fix as normal.
|
|
||||||
|
|
||||||
To submit the update using Arcanist, run `arc diff --update <PhabricatorDifferentialNumber>`.
|
|
||||||
|
|
||||||
For `moz-phab` run in the same way as the initial submission with the same arguments, that is, specifying the full original range of commits. Note that, while inserting and amending commits should work fine, reordering commits is not yet supported, and deleting commits will leave the associated revisions open, which should be abandoned manually
|
|
|
@ -1,184 +0,0 @@
|
||||||
---
|
|
||||||
layout: default
|
|
||||||
title: GeckoView Contributor Guide
|
|
||||||
summary: Guide to setting up as a contributor to GeckoView.
|
|
||||||
tags: [GeckoView,Gecko,mozilla,android,WebView,mobile,mozilla-central,setup,get started,compile,build,deploy,bug fix,submit,patch,arcanist,arc,moz-phab,phabricator]
|
|
||||||
nav_exclude: true
|
|
||||||
exclude: true
|
|
||||||
---
|
|
||||||
## Table of contents
|
|
||||||
{: .no_toc .text-delta }
|
|
||||||
|
|
||||||
1. TOC
|
|
||||||
{:toc}
|
|
||||||
|
|
||||||
# GeckoView Contributor Quick Start Guide
|
|
||||||
|
|
||||||
This is a guide for developers who want to contribute to the GeckoView project. If you want to get started using GeckoView in your app then you should refer to the [wiki](https://wiki.mozilla.org/Mobile/GeckoView#Get_Started).
|
|
||||||
|
|
||||||
You may also be interested in how to get up and running with [Firefox For Android](https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Build_Instructions/Simple_Firefox_for_Android_build).
|
|
||||||
|
|
||||||
## Get set up with Mozilla Central
|
|
||||||
|
|
||||||
The GeckoView codebase is part of the main Firefox tree and can be found in `mozilla-central`. You will need to get set up as a contributor to Firefox in order to contribute to GeckoView. To get set up with `mozilla-central`, follow the [Quick Start Guide for Git Users](mc-quick-start), or the [Contributing to the Mozilla code base](https://developer.mozilla.org/docs/Mozilla/Developer_guide/Introduction) guide on [MDN](https://developer.mozilla.org/) for Mercurial users.
|
|
||||||
|
|
||||||
Once you have a copy of `mozilla-central`, you will need to build GeckoView.
|
|
||||||
|
|
||||||
## Bootstrap Gecko
|
|
||||||
Bootstrap configures everything for GeckoView and Fennec development.
|
|
||||||
|
|
||||||
* Ensure you have `mozilla-central` checked out. If this is the first time you are doing this, it may take some time.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git checkout central/default
|
|
||||||
```
|
|
||||||
If you are on a mac, you will need to have the Xcode build tools installed. You can do this by either [installing Xcode](https://developer.apple.com/xcode/) or installing only the tools from the command line by running `xcode-select --install` and following the on screen instructions. Use the ` --no-interactive` argument to automatically accept any license agreements.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./mach bootstrap [ --no-interactive]
|
|
||||||
```
|
|
||||||
* Choose option `4. Firefox for Android` for GeckoView development. This will give you a version of Gecko configured for Android that has not bundled the native code into embedded libraries so you can amend the code.
|
|
||||||
* Say Y to all configuration options
|
|
||||||
* Once `mach bootstrap` is complete it will tell you to copy and paste some configuration into your `mozconfig` file. The `mozconfig` file can be found in the root of your `gecko` repo - or create a file called `mozconfig` if it does not exist. Check that the correct value is associated with the `--target` argument as this may not correctly match your setup. Copy the file contents from the `mach bootstrap` output into your file and save in the root directory of your project.
|
|
||||||
|
|
||||||
## Build from the command line
|
|
||||||
|
|
||||||
In order to pick up the configuration changes we just made we need to build from the command line. This will update generated sources, compile native code, and produce GeckoView AARs and example and test APKs.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./mach build
|
|
||||||
```
|
|
||||||
|
|
||||||
## Build Using Android Studio
|
|
||||||
|
|
||||||
* Install [Android Studio](https://developer.android.com/studio/install).
|
|
||||||
* Disable Instant Run. This is because Fennec and the Geckoview Example app cannot deploy with Instant Run on.
|
|
||||||
* Select Android Studio > Preferences from the menu bar
|
|
||||||
* Navigate to Build, Execution, Deployment > Instant Run.
|
|
||||||
* Uncheck the box that reads `Enable Instant Run to hot swap code/resource changes on deploy`.
|
|
||||||
|
|
||||||
![alt text]({{ site.url }}/assets/DisableInstantRun.png "Disable Instant Run")
|
|
||||||
* Choose File->Open from the toolbar
|
|
||||||
* Navigate to the root of your `mozilla-central` source directory and click "Open"
|
|
||||||
* Click yes if it asks if you want to use the gradle wrapper.
|
|
||||||
* Wait for the project to index and gradle to sync. Once synced, the workspace will reconfigure to display the different projects.
|
|
||||||
* annotations contains custom annotations used inside GeckoView and Fennec.
|
|
||||||
* app is Fennec - Firefox for Android. Here is where you will find code specific to that app.
|
|
||||||
* geckoview is the GeckoView project. Here is all the Java files related to GeckoView
|
|
||||||
* geckoview_example is an example browser built using GeckoView.
|
|
||||||
* omnijar contains the parts of Gecko and GeckoView that are not written in Java or Kotlin
|
|
||||||
* thirdparty contains third party code that Fennec and GeckoView use.
|
|
||||||
|
|
||||||
![alt text]({{ site.url }}/assets/GeckoViewStructure.png "GeckoView Structure")
|
|
||||||
|
|
||||||
Now you're set up and ready to go.
|
|
||||||
|
|
||||||
**Important: at this time, building from Android Studio or directly from Gradle does not (re-)compile native code, including C++ and Rust.** This means you will need to run `mach build` yourself to pick up changes to native code. [Bug 1509539](https://bugzilla.mozilla.org/show_bug.cgi?id=1509539) tracks making Android Studio and Gradle do this automatically.
|
|
||||||
|
|
||||||
## Performing a bug fix
|
|
||||||
|
|
||||||
One you have got GeckoView building and running, you will want to start contributing. There is a general guide to [Performing a Bug Fix for Git Developers](contributing-to-mc) for you to follow. To contribute to GeckoView specifically, you will need the following additional information.
|
|
||||||
|
|
||||||
### Running tests locally
|
|
||||||
|
|
||||||
To ensure that your patch does not break existing functionality in GeckoView, you can run the junit test suite with the following command
|
|
||||||
|
|
||||||
```
|
|
||||||
./mach geckoview-junit
|
|
||||||
```
|
|
||||||
|
|
||||||
This command also allows you to run individual tests or test classes, e.g.
|
|
||||||
|
|
||||||
```
|
|
||||||
./mach geckoview-junit org.mozilla.geckoview.test.NavigationDelegateTest
|
|
||||||
./mach geckoview-junit org.mozilla.geckoview.test.NavigationDelegateTest#loadUnknownHost
|
|
||||||
```
|
|
||||||
|
|
||||||
### Updating the changelog and API documentation
|
|
||||||
|
|
||||||
If the patch that you want to submit changes the public API for GeckoView, you must ensure that the API documentation is kept up to date. To check whether your patch has altered the API, run the following command.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./mach lint --linter android-api-lint
|
|
||||||
```
|
|
||||||
|
|
||||||
The output of this command will inform you if any changes you have made break the existing API. Review the changes and follow the instructions it provides.
|
|
||||||
|
|
||||||
If the linter asks you to update the changelog, please ensure that you follow the correct format for changelog entries. Under the heading for the next release version, add a new entry for the changes that you are making to the API, along with links to any relevant files, and bug number e.g.
|
|
||||||
|
|
||||||
{% raw %}
|
|
||||||
```
|
|
||||||
- Added [`GeckoRuntimeSettings.Builder#aboutConfigEnabled`][71.12] to control whether or
|
|
||||||
not `about:config` should be available.
|
|
||||||
([bug 1540065]({{bugzilla}}1540065))
|
|
||||||
|
|
||||||
[71.12]: {{javadoc_uri}}/GeckoRuntimeSettings.Builder.html#aboutConfigEnabled-boolean-
|
|
||||||
```
|
|
||||||
{% endraw %}
|
|
||||||
|
|
||||||
### Submitting to the `try` server
|
|
||||||
|
|
||||||
It is advisable to run your tests before submitting your patch. You can do this using Mozilla's `try` server. To submit a GeckoView patch to `try` before submitting it for review, type:
|
|
||||||
```bash
|
|
||||||
./mach try fuzzy -q "android"
|
|
||||||
```
|
|
||||||
|
|
||||||
This will run all of the Android test suite. If your patch passes on `try` you can be (fairly) confident that it will land successfully after review.
|
|
||||||
|
|
||||||
### Tagging a reviewer
|
|
||||||
|
|
||||||
When submitting a patch to Phabricator, if you know who you want to review your patch, put their Phabricator handle against the `reviewers` field.
|
|
||||||
|
|
||||||
If you don't know who to tag for a review in the Phabricator submission message, leave the field blank and, after submission, follow the link to the patch in Phabricator and scroll to the bottom of the screen until you see the comment box.
|
|
||||||
* Select the `Add Action` drop down and pick the `Change Reviewers` option.
|
|
||||||
* In the presented box, add `geckoview-reviewers`. Selecting this group as the reviewer will notify all the members of the GeckoView team there is a patch to review.
|
|
||||||
* Click `Submit` to submit the reviewer change request.
|
|
||||||
|
|
||||||
## Include GeckoView as a dependency
|
|
||||||
|
|
||||||
If you want to include a development version of GeckoView as a dependency inside another app, you must link to a local copy. There are several ways to achieve this, but the preferred way is to use Gradle's *dependency substitution* mechanism, for which there is first-class support in `mozilla-central` and a pattern throughout Mozilla's GeckoView-consuming ecosystem.
|
|
||||||
|
|
||||||
The good news is that `mach build` produces everything you need, so that after the configuration below, you should find that the following commands rebuild your local GeckoView and then consume your local version in the downstream project.
|
|
||||||
|
|
||||||
```sh
|
|
||||||
cd /path/to/mozilla-central && ./mach build
|
|
||||||
cd /path/to/project && ./gradlew assembleDebug
|
|
||||||
```
|
|
||||||
|
|
||||||
**Be sure that your `mozconfig` specifies the correct `--target` argument for your target device.** Many projects use "ABI splitting" to include only the target device's native code libraries in APKs deployed to the device. On x86-64 and aarch64 devices, this can result in GeckoView failing to find any libraries, because valid x86 and ARM libraries were not included in a deployed APK. Avoid this by setting `--target` to the exact ABI that your device supports.
|
|
||||||
|
|
||||||
### Dependency substiting your local GeckoView into a Mozilla project
|
|
||||||
|
|
||||||
Most GeckoView-consuming projects produced by Mozilla support dependency substitution via `local.properties`. These projects include:
|
|
||||||
* [Fenix](https://github.com/mozilla-mobile/fenix)
|
|
||||||
* [reference-browser](https://github.com/mozilla-mobile/reference-browser)
|
|
||||||
* [android-components](https://github.com/mozilla-mobile/android-components)
|
|
||||||
* [Firefox Reality](https://github.com/MozillaReality/FirefoxReality)
|
|
||||||
Simply edit (or create) the file `local.properties` in the project root and include a line like:
|
|
||||||
```properties
|
|
||||||
dependencySubstitutions.geckoviewTopsrcdir=/path/to/mozilla-central
|
|
||||||
```
|
|
||||||
The default object directory -- the one that a plain `mach build` discovers -- will be used. You can optionally specify a particular object directory with an additional line like:
|
|
||||||
```properties
|
|
||||||
dependencySubstitutions.geckoviewTopobjdir=/path/to/object-directory
|
|
||||||
```
|
|
||||||
|
|
||||||
With these lines, the GeckoView-consuming project should use the GeckoView AAR produced by `mach build` in your local `mozilla-central`.
|
|
||||||
|
|
||||||
**Remember to remove the lines in `local.properties` when you want to return to using the published GeckoView builds!**
|
|
||||||
|
|
||||||
### Dependency substituting your local GeckoView into a non-Mozilla project
|
|
||||||
|
|
||||||
In projects that don't have first-class support for dependency substitution already, you can do the substitution yourself. See the documentation in [substitue-local-geckoview.gradle](https://hg.mozilla.org/mozilla-central/file/tip/substitute-local-geckoview.gradle), but roughly: in each Gradle project that consumes GeckoView, i.e., in each `build.gradle` with a `dependencies { ... 'org.mozilla.geckoview:geckoview-...' }` block, include lines like:
|
|
||||||
|
|
||||||
```groovy
|
|
||||||
ext.topsrcdir = "/path/to/mozilla-central"
|
|
||||||
ext.topobjdir = "/path/to/object-directory" // Optional.
|
|
||||||
apply from: "${topsrcdir}/substitute-local-geckoview.gradle"
|
|
||||||
```
|
|
||||||
|
|
||||||
**Remember to remove the lines from all `build.gradle` files when you want to return to using the published GeckoView builds!**
|
|
||||||
|
|
||||||
## Next Steps
|
|
||||||
|
|
||||||
- Get started with [Native Debugging](native-debugging)
|
|
|
@ -1,19 +0,0 @@
|
||||||
---
|
|
||||||
layout: default
|
|
||||||
title: Contributing to GeckoView
|
|
||||||
nav_order: 4
|
|
||||||
---
|
|
||||||
|
|
||||||
# Contributor Site
|
|
||||||
|
|
||||||
If you want to run GeckoView from code, or start contributing back to the project, here you will find resources to help you do that.
|
|
||||||
|
|
||||||
- [GeckoView Contributor Quick Start Guide](geckoview-quick-start): Get GeckoView set up for development.
|
|
||||||
- [Mozilla Central Quick Start Guide](mc-quick-start):
|
|
||||||
Get Mozilla Central set up for development.
|
|
||||||
- [Mozilla Central Contributor Guide](contributing-to-mc):
|
|
||||||
Get started as a contributor to Mozilla Central.
|
|
||||||
- [Guide to Native Debugging in Android Studio](native-debugging):
|
|
||||||
Set up Android Studio for debugging native code.
|
|
||||||
|
|
||||||
If there is documentation that you feel is missing, or an existing document doesn't cover the aspect that you are looking for, please request it by raising an issue on our [documentation site](https://github.com/mozilla/geckoview/issues).
|
|
|
@ -1,129 +0,0 @@
|
||||||
---
|
|
||||||
layout: default
|
|
||||||
title: Mozilla Central Quick Start
|
|
||||||
summary: Guide to setting up as a Git contributor to mozilla-central.
|
|
||||||
tags: [GeckoView,Gecko,mozilla,android,WebView,mobile,mozilla-central,setup,compiling,mercurial,git-cinnabar]
|
|
||||||
nav_exclude: true
|
|
||||||
exclude: true
|
|
||||||
---
|
|
||||||
## Table of contents
|
|
||||||
{: .no_toc .text-delta }
|
|
||||||
|
|
||||||
1. TOC
|
|
||||||
{:toc}
|
|
||||||
|
|
||||||
# Firefox Developer Git Quick Start Guide
|
|
||||||
|
|
||||||
Getting setup to as a first time Mozilla contributor is hard. There are plenty of guides out there to help you get started as a contributor, but many of the new contributor guides out of date often more current ones are aimed at more experienced contributors. If you want to review these guides, you can find several linked to from [Contributing to the Mozilla code base](https://developer.mozilla.org/docs/Mozilla/Developer_guide/Introduction) on [MDN](https://developer.mozilla.org/).
|
|
||||||
|
|
||||||
This guide will take you through setting up as a contributor to `mozilla-central`, the Firefox main repository, as a git user.
|
|
||||||
|
|
||||||
## Setup
|
|
||||||
|
|
||||||
The first thing you will need is to install Mercurial as this is the VCS that `mozilla-central` uses.
|
|
||||||
|
|
||||||
### Mac
|
|
||||||
|
|
||||||
#### Homebrew
|
|
||||||
|
|
||||||
```bash
|
|
||||||
brew install mercurial
|
|
||||||
```
|
|
||||||
|
|
||||||
#### macports
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo port install mercurial
|
|
||||||
```
|
|
||||||
|
|
||||||
### Linux
|
|
||||||
|
|
||||||
#### apt
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo apt-get install mercurial
|
|
||||||
```
|
|
||||||
|
|
||||||
Alternatively you can install [Mercurial directly](https://www.mercurial-scm.org/wiki/Download).
|
|
||||||
|
|
||||||
Check that you have successfully installed Mercurial by running:
|
|
||||||
```bash
|
|
||||||
hg --version
|
|
||||||
```
|
|
||||||
|
|
||||||
If you are an experienced git user and are unfamiliar with Mercurial, you may want to install `git-cinnabar`. Cinnabar is a git remote helper that allows you to interact with Mercurial repos using git semantics.
|
|
||||||
|
|
||||||
## git-cinnabar
|
|
||||||
|
|
||||||
There is a Homebrew install option for `git-cinnabar`, but this did not work for me, nor did the installer option. Using these tools, when I tried to clone the Mercurial repo it hung and did not complete. I had to do a manual install before I could use `git-cinnabar` successfully to download a Mercurial repo. If you would like to try either of these option, however, here they are:
|
|
||||||
|
|
||||||
### Mac
|
|
||||||
#### Homebrew
|
|
||||||
|
|
||||||
```bash
|
|
||||||
brew install git-cinnabar
|
|
||||||
```
|
|
||||||
|
|
||||||
### All Platforms
|
|
||||||
#### Installer
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git cinnabar download
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Manual installation
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone https://github.com/glandium/git-cinnabar.git && cd git-cinnabar
|
|
||||||
make
|
|
||||||
export PATH="$PATH:/somewhere/git-cinnabar/"
|
|
||||||
echo PATH="$PATH:/somewhere/git-cinnabar/" >> ~/.bash_profile
|
|
||||||
export PATH="$PATH:/somewhere/git-cinnabar/git-core/bin-wrappers"
|
|
||||||
echo PATH="$PATH:/somewhere/git-cinnabar/git-core/bin-wrappers" >> ~/.bash_profile
|
|
||||||
```
|
|
||||||
|
|
||||||
`git-cinnabar`'s creator, [glandium](https://glandium.org/), has written a number of posts about setting up for Firefox Development with git. This [post](https://glandium.org/blog/?page_id=3438) is the one that has formed the basis for this walkthrough.
|
|
||||||
|
|
||||||
In synopsis:
|
|
||||||
|
|
||||||
* initialize an empty git repository
|
|
||||||
```bash
|
|
||||||
git init gecko && cd gecko
|
|
||||||
```
|
|
||||||
|
|
||||||
* Configure git:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git config fetch.prune true
|
|
||||||
git config push.default upstream
|
|
||||||
```
|
|
||||||
|
|
||||||
* Add remotes for your repositories. There are several to choose from, `central`, `inbound`, `beta`, `release` etc. but in reality, if you plan on using Phabricator, which is Firefox's preferred patch submission system, you only need to set up `central`. It might be advisable to have access to `inbound` however, if you want to work on a version of Firefox that is queued for release. This guide will be focussed on Phabricator.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git remote add central hg::https://hg.mozilla.org/mozilla-central -t branches/default/tip
|
|
||||||
git remote add inbound hg::https://hg.mozilla.org/integration/mozilla-inbound -t branches/default/tip
|
|
||||||
git remote set-url --push central hg::ssh://hg.mozilla.org/mozilla-central
|
|
||||||
git remote set-url --push inbound hg::ssh://hg.mozilla.org/integration/mozilla-inbound
|
|
||||||
```
|
|
||||||
* Expose the branch tip to get quick access with some easy names.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git config remote.central.fetch +refs/heads/branches/default/tip:refs/remotes/central/default
|
|
||||||
git config remote.inbound.fetch +refs/heads/branches/default/tip:refs/remotes/inbound/default
|
|
||||||
```
|
|
||||||
* Setup a remote for the try server. The try server is an easy way to test a patch without actually checking the patch into the core repository. Your code will go through the same tests as a `mozilla-central` push, and you'll be able to download builds if you wish.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git remote add try hg::https://hg.mozilla.org/try
|
|
||||||
git config remote.try.skipDefaultUpdate true
|
|
||||||
git remote set-url --push try hg::ssh://hg.mozilla.org/try
|
|
||||||
git config remote.try.push +HEAD:refs/heads/branches/default/tip
|
|
||||||
```
|
|
||||||
* Now update all the remotes. This performs a `git fetch` on all the remotes. Mozilla Central is a _large_ repository. Be prepared for this to take a very long time.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git remote update
|
|
||||||
```
|
|
||||||
|
|
||||||
All that's left to do now is pick a bug to fix and [submit a patch](contributing-to-mc).
|
|
|
@ -1,114 +0,0 @@
|
||||||
---
|
|
||||||
layout: default
|
|
||||||
title: Debugging Native Code
|
|
||||||
summary: How to set up native debugging for GeckoView using Android Studio.
|
|
||||||
tags: [GeckoView,Gecko,mozilla,android,WebView,mobile,debugging,native,android studio]
|
|
||||||
nav_exclude: true
|
|
||||||
exclude: true
|
|
||||||
---
|
|
||||||
## Table of contents
|
|
||||||
{: .no_toc .text-delta }
|
|
||||||
|
|
||||||
1. TOC
|
|
||||||
{:toc}
|
|
||||||
|
|
||||||
# Debugging Native Code in Android Studio.
|
|
||||||
If you want to work on the C++ code that powers GeckoView, you will need to be able to perform native debugging inside Android Studio. This article will guide you through how to do that.
|
|
||||||
|
|
||||||
If you need to get set up with GeckoView for the first time, follow the [Quick Start Guide](geckoview-quick-start).
|
|
||||||
|
|
||||||
## Perform a debug build of Gecko.
|
|
||||||
1. Edit your `mozconfig` file and add the following lines. These will ensure that the build includes debug checks and symbols.
|
|
||||||
|
|
||||||
```
|
|
||||||
ac_add_options --enable-debug
|
|
||||||
ac_add_options --with-android-ndk="<path>/.mozbuild/android-ndk-r17b"
|
|
||||||
```
|
|
||||||
2. Ensure that the following lines are commented out in your `mozconfig` if present. `./mach configure` will not allow artifact builds to be enabled when generating a debug build.
|
|
||||||
|
|
||||||
```
|
|
||||||
# ac_add_options --enable-artifact-builds
|
|
||||||
```
|
|
||||||
3. To be absolutely sure that Android Studio will pick up your debug symbols, the first time you perform a debug build it is best to clobber your `MOZ_OBJDIR`. Subsequent builds should not need this step.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./mach clobber
|
|
||||||
```
|
|
||||||
4. Build as usual. Because this is a debug build, and because you have clobbered your `MOZ_OBJDIR`, this will take a long time. Subsequent builds will be incremental and take less time, so go make yourself a cup of your favourite beverage.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./mach build
|
|
||||||
```
|
|
||||||
## Set up lldb to find your symbols
|
|
||||||
Edit your `~/.lldbinit` file (or create one if one does not already exist) and add the following lines.
|
|
||||||
|
|
||||||
The first line tells LLDB to enable inline breakpoints - Android Studio will need this if you want to use visual breakpoints.
|
|
||||||
|
|
||||||
The remaining lines tell LLDB where to go to find the symbols for debugging.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
settings set target.inline-breakpoint-strategy always
|
|
||||||
settings append target.exec-search-paths <PATH>/objdir-android-opt/toolkit/library/build
|
|
||||||
settings append target.exec-search-paths <PATH>/objdir-android-opt/mozglue/build
|
|
||||||
```
|
|
||||||
# Set up Android Studio to perform native debugging.
|
|
||||||
|
|
||||||
1. Edit the configuration that you want to debug by clicking `Run -> Edit Configurations...` and selecting the correct configuration from the options on the left hand side of the resulting window.
|
|
||||||
2. Select the `Debugger` tab.
|
|
||||||
3. Select `Dual` from the `Debug type` select box. Dual will allow debugging of both native and Java code in the same session. It is possible to use `Native`, but it will only allow for debugging native code, and it's frequently necessary to break in the Java code that configures Gecko and child processes in order to attach debuggers at the correct times.
|
|
||||||
4. Under `Symbol Directories`, add a new path pointing to `<PATH>/objdir-android-opt/toolkit/library/build`, the same path that you entered into your `.lldbinit` file.
|
|
||||||
5. Select `Apply` and `OK` to close the window.
|
|
||||||
|
|
||||||
# Debug Native code in Android Studio
|
|
||||||
|
|
||||||
1. The first time you are running a debug session for your app, it's best to start from a completely clean build. Click `Build -> Rebuild Project` to clean and rebuild. You can also choose to remove any existing builds from your emulator to be completely sure, but this may not be neccessary.
|
|
||||||
2. If using Android Studio visual breakpoints, set your breakpoints in your native code.
|
|
||||||
3. Run the app in debug mode as usual.
|
|
||||||
4. When debugging Fennec or geckoview_example, you will almost immediately hit a breakpoint in `ElfLoader.cpp`. This is expected. If you are not using Android Studio visual breakpoints, you can set your breakpoints here using the lldb console that is available now this breakpoint has been hit. To set a breakpoint, select the app tab (if running Dual, there will also be an `<app> java` tab) from the debug window, and then select the `lldb` console tab. Type the following into the console:
|
|
||||||
|
|
||||||
```lldb
|
|
||||||
b <file>.cpp:<line number>
|
|
||||||
```
|
|
||||||
5. Once your breakpoints have been set, click the continue execution button to move beyond the `ElfLoader` breakpoint and your newly set native breakpoints should be hit. Debug as usual.
|
|
||||||
|
|
||||||
## Attaching debuggers to content and other child processes
|
|
||||||
|
|
||||||
Internally, GeckoView has a multi-process architecture. The main Gecko process lives in the main Android process, but content rendering and some other functions live in child processes. This balances load, ensures certain critical security properties, and allows GeckoView to recover if content processes become unresponsive or crash. However, it's generally delicate to debug child processes because they come and go.
|
|
||||||
|
|
||||||
The general approach is to make the Java code in the child process that you want to debug wait for a Java debugger at startup, and then to connect such a Java debugger manually from the Android Studio UI.
|
|
||||||
|
|
||||||
[Bug 1522318](https://bugzilla.mozilla.org/show_bug.cgi?id=1522318) added environment variables that makes GeckoView wait for Java debuggers to attach, making this debug process more developer-friendly. See [Configuring GeckoView for Automation](../consumer/docs/automation) for instructions on how to set environment variables that configure GeckoView's runtime environment.
|
|
||||||
|
|
||||||
### Making processes wait for a Java debugger
|
|
||||||
|
|
||||||
The following environment variable makes the main (Gecko) process wait for a Java debugger to connect:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
MOZ_DEBUG_WAIT_FOR_JAVA_DEBUGGER=1
|
|
||||||
```
|
|
||||||
|
|
||||||
This is a superset of Android Studio's built-in debugging support so it's not particularly useful (unless you want to attach a different jdwp debugger).
|
|
||||||
|
|
||||||
The following environment variable makes every child process wait for a Java debugger to connect:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
MOZ_DEBUG_CHILD_WAIT_FOR_JAVA_DEBUGGER=
|
|
||||||
```
|
|
||||||
|
|
||||||
Set `MOZ_DEBUG_CHILD_WAIT_FOR_JAVA_DEBUGGER=suffix` in the environment to make child processes with an Android process name ending with `suffix` wait for a Java debugger to connect. For example, the following environment variable makes every child content process wait for a Java debugger to connect:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
MOZ_DEBUG_CHILD_WAIT_FOR_JAVA_DEBUGGER=:tab
|
|
||||||
```
|
|
||||||
|
|
||||||
### Attaching a Java debugger to a waiting child process
|
|
||||||
|
|
||||||
This is standard: follow the [Android Studio instructions](https://developer.android.com/studio/debug/index.html#attach-debugger). You must attach a Java debugger, so you almost certainly want to attach a `Dual` debugger and you definitely can't attach only a `Native` debugger.
|
|
||||||
|
|
||||||
Determining the correct process to attach to is a little tricky because the mapping from process ID (pid) to process name is not always clear. Gecko content child processes are suffixed `:tab` at this time.
|
|
||||||
|
|
||||||
If you attach `Dual` debuggers to both the main process and a content child process, you will have four (4!) debug tabs to manage in Android Studio, which is awkward. Android Studio doesn't appear to configure attached debuggers in the same way that it configures debuggers connecting to launched Run Configurations, so you may need to manually configure search paths -- i.e., you may need to invoke the contents of your `lldbinit` file in the appropriate `lldb` console by hand, using an invocation like `command source /absolute/path/to/topobjdir/lldbinit`.
|
|
||||||
|
|
||||||
Android Studio also doesn't appear to support targeting breakpoints from the UI (say, from clicking in a gutter) to specific debug tabs, so you may also need to set breakpoints in the appropriate `lldb` console by hand.
|
|
||||||
|
|
||||||
Managing more debug tabs may require different approaches.
|
|
|
@ -1,7 +1,4 @@
|
||||||
<head>
|
<head>
|
||||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
|
||||||
{% if page.title %}
|
{% if page.title %}
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
|
||||||
<li class="navigation-list-item{% if page.url contains '/javadoc/mozilla-central/index.html' %} active{% endif %}">
|
<li class="navigation-list-item{% if page.url contains '/javadoc/mozilla-central/index.html' %} active{% endif %}">
|
||||||
<a href="{{ site.url }}{{ site.baseurl }}/javadoc/mozilla-central/index.html" class="navigation-list-link{% if page.url contains '/javadoc/mozilla-central/index.html' %} active{% endif %}">API Documentation</a>
|
<a href="{{ site.url }}{{ site.baseurl }}/javadoc/mozilla-central/index.html" class="navigation-list-link{% if page.url contains '/javadoc/mozilla-central/index.html' %} active{% endif %}">API Documentation</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
|
||||||
<nav role="navigation" aria-label="Main navigation">
|
<nav role="navigation" aria-label="Main navigation">
|
||||||
<ul class="navigation-list">
|
<ul class="navigation-list">
|
||||||
{% assign pages_list = site.html_pages | sort:"nav_order" %}
|
{% assign pages_list = site.html_pages | sort:"nav_order" %}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
|
||||||
<html lang="en-us">
|
<html lang="en-us">
|
||||||
{% include head.html %}
|
{% include head.html %}
|
||||||
<body>
|
<body>
|
||||||
|
|
|
@ -57,7 +57,7 @@ public class GeckoViewActivity extends AppCompatActivity {
|
||||||
|
|
||||||
### Android Permissions
|
### Android Permissions
|
||||||
|
|
||||||
Android permissions are requested whenever a site wants access to a device's navigation or input capabilities.
|
Android permissions are requested whenever a site wants access to a device's navigation or input capabilites.
|
||||||
|
|
||||||
The user will often need to grant these Android permissions to the app alongside granting the Content or Media site permissions.
|
The user will often need to grant these Android permissions to the app alongside granting the Content or Media site permissions.
|
||||||
|
|
||||||
|
|
|
@ -323,8 +323,8 @@ This allows bidirectional communication between the app and the WebExtension.
|
||||||
[17]: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/permissions
|
[17]: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/permissions
|
||||||
[18]: {{ site.url }}{{ site.baseurl }}/javadoc/mozilla-central/org/mozilla/geckoview/WebExtension.MessageDelegate.html
|
[18]: {{ site.url }}{{ site.baseurl }}/javadoc/mozilla-central/org/mozilla/geckoview/WebExtension.MessageDelegate.html
|
||||||
[19]: https://developer.mozilla.org/en-US/docs/Web/Manifest
|
[19]: https://developer.mozilla.org/en-US/docs/Web/Manifest
|
||||||
[20]: https://searchfox.org/mozilla-central/source/mobile/android/examples/extensions/messaging_example/
|
[20]: https://github.com/mozilla/geckoview/tree/gh-pages/examples/extensions/MessagingExample/
|
||||||
[21]: https://searchfox.org/mozilla-central/source/mobile/android/examples/extensions/port_messaging_example/
|
[21]: https://github.com/mozilla/geckoview/tree/gh-pages/examples/extensions/PortMessagingExample/
|
||||||
[22]: {{ site.url }}{{ site.baseurl }}/javadoc/mozilla-central/org/mozilla/geckoview/WebExtension.Flags.html#ALLOW_CONTENT_MESSAGING
|
[22]: {{ site.url }}{{ site.baseurl }}/javadoc/mozilla-central/org/mozilla/geckoview/WebExtension.Flags.html#ALLOW_CONTENT_MESSAGING
|
||||||
[23]: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json
|
[23]: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json
|
||||||
[24]: {{ site.url }}{{ site.baseurl }}/javadoc/mozilla-central/org/mozilla/geckoview/GeckoRuntime.html
|
[24]: {{ site.url }}{{ site.baseurl }}/javadoc/mozilla-central/org/mozilla/geckoview/GeckoRuntime.html
|
||||||
|
|
|
@ -97,7 +97,7 @@ git checkout "your-branch-with-commits"
|
||||||
arc diff
|
arc diff
|
||||||
```
|
```
|
||||||
|
|
||||||
* If you have any uncommitted files, Arcanist will ask if you want to commit them.
|
* If you have any uncommited files, Arcanist will ask if you want to commit them.
|
||||||
* If you have any files in the path not added to git Arcanist will ask if you want to ignore them.
|
* If you have any files in the path not added to git Arcanist will ask if you want to ignore them.
|
||||||
* After formatting your patch, Arcanist will open a nano/emacs file for you to enter the commit details. If you have many individual git commits in your arcanist diff then the first line of the first commit message will become the patch title, and the rest of the commit, plus the messages for the other commits in the patch will form the summary.
|
* After formatting your patch, Arcanist will open a nano/emacs file for you to enter the commit details. If you have many individual git commits in your arcanist diff then the first line of the first commit message will become the patch title, and the rest of the commit, plus the messages for the other commits in the patch will form the summary.
|
||||||
* Ensure you have entered the bug number against the `Bug #` field.
|
* Ensure you have entered the bug number against the `Bug #` field.
|
||||||
|
@ -138,7 +138,7 @@ git log
|
||||||
```bash
|
```bash
|
||||||
moz-phab submit [start_rev] [end_rev]
|
moz-phab submit [start_rev] [end_rev]
|
||||||
```
|
```
|
||||||
* You will receive a Phabricator link for each commit in the set.
|
* You will recieve a Phabricator link for each commit in the set.
|
||||||
|
|
||||||
### Updating a patch
|
### Updating a patch
|
||||||
|
|
||||||
|
|
|
@ -98,7 +98,7 @@ git config fetch.prune true
|
||||||
git config push.default upstream
|
git config push.default upstream
|
||||||
```
|
```
|
||||||
|
|
||||||
* Add remotes for your repositories. There are several to choose from, `central`, `inbound`, `beta`, `release` etc. but in reality, if you plan on using Phabricator, which is Firefox's preferred patch submission system, you only need to set up `central`. It might be advisable to have access to `inbound` however, if you want to work on a version of Firefox that is queued for release. This guide will be focused on Phabricator.
|
* Add remotes for your repositories. There are several to choose from, `central`, `inbound`, `beta`, `release` etc. but in reality, if you plan on using Phabricator, which is Firefox's preferred patch submission system, you only need to set up `central`. It might be advisable to have access to `inbound` however, if you want to work on a version of Firefox that is queued for release. This guide will be focussed on Phabricator.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git remote add central hg::https://hg.mozilla.org/mozilla-central -t branches/default/tip
|
git remote add central hg::https://hg.mozilla.org/mozilla-central -t branches/default/tip
|
||||||
|
|
|
@ -61,7 +61,7 @@ settings append target.exec-search-paths <PATH>/objdir-android-opt/mozglue/build
|
||||||
|
|
||||||
# Debug Native code in Android Studio
|
# Debug Native code in Android Studio
|
||||||
|
|
||||||
1. The first time you are running a debug session for your app, it's best to start from a completely clean build. Click `Build -> Rebuild Project` to clean and rebuild. You can also choose to remove any existing builds from your emulator to be completely sure, but this may not be necessary.
|
1. The first time you are running a debug session for your app, it's best to start from a completely clean build. Click `Build -> Rebuild Project` to clean and rebuild. You can also choose to remove any existing builds from your emulator to be completely sure, but this may not be neccessary.
|
||||||
2. If using Android Studio visual breakpoints, set your breakpoints in your native code.
|
2. If using Android Studio visual breakpoints, set your breakpoints in your native code.
|
||||||
3. Run the app in debug mode as usual.
|
3. Run the app in debug mode as usual.
|
||||||
4. When debugging Fennec or geckoview_example, you will almost immediately hit a breakpoint in `ElfLoader.cpp`. This is expected. If you are not using Android Studio visual breakpoints, you can set your breakpoints here using the lldb console that is available now this breakpoint has been hit. To set a breakpoint, select the app tab (if running Dual, there will also be an `<app> java` tab) from the debug window, and then select the `lldb` console tab. Type the following into the console:
|
4. When debugging Fennec or geckoview_example, you will almost immediately hit a breakpoint in `ElfLoader.cpp`. This is expected. If you are not using Android Studio visual breakpoints, you can set your breakpoints here using the lldb console that is available now this breakpoint has been hit. To set a breakpoint, select the app tab (if running Dual, there will also be an `<app> java` tab) from the debug window, and then select the `lldb` console tab. Type the following into the console:
|
||||||
|
|
До Ширина: | Высота: | Размер: 2.9 KiB После Ширина: | Высота: | Размер: 2.9 KiB |
До Ширина: | Высота: | Размер: 4.8 KiB После Ширина: | Высота: | Размер: 4.8 KiB |
До Ширина: | Высота: | Размер: 2.0 KiB После Ширина: | Высота: | Размер: 2.0 KiB |
До Ширина: | Высота: | Размер: 2.7 KiB После Ширина: | Высота: | Размер: 2.7 KiB |
До Ширина: | Высота: | Размер: 4.4 KiB После Ширина: | Высота: | Размер: 4.4 KiB |
До Ширина: | Высота: | Размер: 6.7 KiB После Ширина: | Высота: | Размер: 6.7 KiB |
До Ширина: | Высота: | Размер: 6.2 KiB После Ширина: | Высота: | Размер: 6.2 KiB |
До Ширина: | Высота: | Размер: 10 KiB После Ширина: | Высота: | Размер: 10 KiB |
До Ширина: | Высота: | Размер: 8.9 KiB После Ширина: | Высота: | Размер: 8.9 KiB |
До Ширина: | Высота: | Размер: 15 KiB После Ширина: | Высота: | Размер: 15 KiB |
До Ширина: | Высота: | Размер: 2.9 KiB После Ширина: | Высота: | Размер: 2.9 KiB |
До Ширина: | Высота: | Размер: 4.8 KiB После Ширина: | Высота: | Размер: 4.8 KiB |
До Ширина: | Высота: | Размер: 2.0 KiB После Ширина: | Высота: | Размер: 2.0 KiB |
До Ширина: | Высота: | Размер: 2.7 KiB После Ширина: | Высота: | Размер: 2.7 KiB |
До Ширина: | Высота: | Размер: 4.4 KiB После Ширина: | Высота: | Размер: 4.4 KiB |
До Ширина: | Высота: | Размер: 6.7 KiB После Ширина: | Высота: | Размер: 6.7 KiB |
До Ширина: | Высота: | Размер: 6.2 KiB После Ширина: | Высота: | Размер: 6.2 KiB |
До Ширина: | Высота: | Размер: 10 KiB После Ширина: | Высота: | Размер: 10 KiB |
До Ширина: | Высота: | Размер: 8.9 KiB После Ширина: | Высота: | Размер: 8.9 KiB |
До Ширина: | Высота: | Размер: 15 KiB После Ширина: | Высота: | Размер: 15 KiB |