Fix initial Android support (#778)
* Add force touches, fix ui focus system and touch screen system * Fix examples README. Update rodio with Android support. Add Android build CI * Alter android metadata in root Cargo.toml
This commit is contained in:
parent
562190f518
commit
7efb1b1887
11
.github/workflows/ci.yml
vendored
11
.github/workflows/ci.yml
vendored
@ -85,6 +85,17 @@ jobs:
|
|||||||
command: check
|
command: check
|
||||||
args: --target wasm32-unknown-unknown --no-default-features --features bevy_winit,x11,hdr,bevy_gltf
|
args: --target wasm32-unknown-unknown --no-default-features --features bevy_winit,x11,hdr,bevy_gltf
|
||||||
|
|
||||||
|
build-android:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Install Android targets
|
||||||
|
run: rustup target add aarch64-linux-android armv7-linux-androideabi
|
||||||
|
- name: Install Cargo APK
|
||||||
|
run: cargo install cargo-apk
|
||||||
|
- name: Build APK
|
||||||
|
run: cargo apk build --example bevy_android
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
25
Cargo.toml
25
Cargo.toml
@ -30,21 +30,6 @@ default = [
|
|||||||
"x11",
|
"x11",
|
||||||
]
|
]
|
||||||
|
|
||||||
supported_android_features = [
|
|
||||||
# cpal is not supported yet
|
|
||||||
# "bevy_audio",
|
|
||||||
"bevy_dynamic_plugin",
|
|
||||||
"bevy_gilrs",
|
|
||||||
"bevy_gltf",
|
|
||||||
"bevy_wgpu",
|
|
||||||
"bevy_winit",
|
|
||||||
"render",
|
|
||||||
"png",
|
|
||||||
"hdr",
|
|
||||||
# "mp3",
|
|
||||||
"x11",
|
|
||||||
]
|
|
||||||
|
|
||||||
profiler = ["bevy_ecs/profiler", "bevy_diagnostic/profiler"]
|
profiler = ["bevy_ecs/profiler", "bevy_diagnostic/profiler"]
|
||||||
wgpu_trace = ["bevy_wgpu/trace"]
|
wgpu_trace = ["bevy_wgpu/trace"]
|
||||||
|
|
||||||
@ -341,10 +326,6 @@ path = "examples/android/bevy_android.rs"
|
|||||||
crate-type = ["cdylib"]
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
[package.metadata.android]
|
[package.metadata.android]
|
||||||
build_targets = [ "aarch64-linux-android", "armv7-linux-androideabi" ]
|
build_targets = ["aarch64-linux-android", "armv7-linux-androideabi"]
|
||||||
target_sdk_version = 28
|
target_sdk_version = 29
|
||||||
min_sdk_version = 28
|
min_sdk_version = 16
|
||||||
|
|
||||||
[[package.metadata.android.feature]]
|
|
||||||
name = "android.hardware.vulkan.level"
|
|
||||||
version = "1"
|
|
||||||
|
@ -22,7 +22,7 @@ bevy_utils = { path = "../bevy_utils", version = "0.2.1" }
|
|||||||
|
|
||||||
# other
|
# other
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
rodio = { version = "0.12", default-features = false }
|
rodio = { version = "0.13", default-features = false }
|
||||||
parking_lot = "0.11.0"
|
parking_lot = "0.11.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
@ -17,6 +17,7 @@ pub mod prelude {
|
|||||||
},
|
},
|
||||||
keyboard::KeyCode,
|
keyboard::KeyCode,
|
||||||
mouse::MouseButton,
|
mouse::MouseButton,
|
||||||
|
touch::{TouchInput, Touches},
|
||||||
Axis, Input,
|
Axis, Input,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,73 @@
|
|||||||
use bevy_app::{EventReader, Events};
|
use bevy_app::{EventReader, Events};
|
||||||
use bevy_ecs::{Local, Res, ResMut};
|
use bevy_ecs::{Local, Res, ResMut};
|
||||||
use bevy_math::Vec2;
|
use bevy_math::Vec2;
|
||||||
use bevy_utils::{HashMap, HashSet};
|
use bevy_utils::HashMap;
|
||||||
|
use core::ops::DerefMut;
|
||||||
|
|
||||||
/// A touch input event
|
/// Represents a touch event
|
||||||
#[derive(Debug, Clone)]
|
///
|
||||||
|
/// Every time the user touches the screen, a new `Start` event with an unique
|
||||||
|
/// identifier for the finger is generated. When the finger is lifted, an `End`
|
||||||
|
/// event is generated with the same finger id.
|
||||||
|
///
|
||||||
|
/// After a `Start` event has been emitted, there may be zero or more `Move`
|
||||||
|
/// events when the finger is moved or the touch pressure changes.
|
||||||
|
///
|
||||||
|
/// The finger id may be reused by the system after an `End` event. The user
|
||||||
|
/// should assume that a new `Start` event received with the same id has nothing
|
||||||
|
/// to do with the old finger and is a new finger.
|
||||||
|
///
|
||||||
|
/// A `Cancelled` event is emitted when the system has canceled tracking this
|
||||||
|
/// touch, such as when the window loses focus, or on iOS if the user moves the
|
||||||
|
/// device against their face.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub struct TouchInput {
|
pub struct TouchInput {
|
||||||
pub phase: TouchPhase,
|
pub phase: TouchPhase,
|
||||||
pub position: Vec2,
|
pub position: Vec2,
|
||||||
|
/// Describes how hard the screen was pressed. May be `None` if the platform
|
||||||
|
/// does not support pressure sensitivity.
|
||||||
///
|
///
|
||||||
/// ## Platform-specific
|
/// ## Platform-specific
|
||||||
///
|
///
|
||||||
|
/// - Only available on **iOS** 9.0+ and **Windows** 8+.
|
||||||
|
pub force: Option<ForceTouch>,
|
||||||
/// Unique identifier of a finger.
|
/// Unique identifier of a finger.
|
||||||
pub id: u64,
|
pub id: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Describes the force of a touch event
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
pub enum ForceTouch {
|
||||||
|
/// On iOS, the force is calibrated so that the same number corresponds to
|
||||||
|
/// roughly the same amount of pressure on the screen regardless of the
|
||||||
|
/// device.
|
||||||
|
Calibrated {
|
||||||
|
/// The force of the touch, where a value of 1.0 represents the force of
|
||||||
|
/// an average touch (predetermined by the system, not user-specific).
|
||||||
|
///
|
||||||
|
/// The force reported by Apple Pencil is measured along the axis of the
|
||||||
|
/// pencil. If you want a force perpendicular to the device, you need to
|
||||||
|
/// calculate this value using the `altitude_angle` value.
|
||||||
|
force: f64,
|
||||||
|
/// The maximum possible force for a touch.
|
||||||
|
///
|
||||||
|
/// The value of this field is sufficiently high to provide a wide
|
||||||
|
/// dynamic range for values of the `force` field.
|
||||||
|
max_possible_force: f64,
|
||||||
|
/// The altitude (in radians) of the stylus.
|
||||||
|
///
|
||||||
|
/// A value of 0 radians indicates that the stylus is parallel to the
|
||||||
|
/// surface. The value of this property is Pi/2 when the stylus is
|
||||||
|
/// perpendicular to the surface.
|
||||||
|
altitude_angle: Option<f64>,
|
||||||
|
},
|
||||||
|
/// If the platform reports the force as normalized, we have no way of
|
||||||
|
/// knowing how much pressure 1.0 corresponds to – we know it's the maximum
|
||||||
|
/// amount of force, but as to how much force, you might either have to
|
||||||
|
/// press really really hard, or not hard at all, depending on the device.
|
||||||
|
Normalized(f64),
|
||||||
|
}
|
||||||
|
|
||||||
/// Describes touch-screen input state.
|
/// Describes touch-screen input state.
|
||||||
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
|
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
|
||||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||||
@ -30,12 +83,15 @@ pub struct TouchSystemState {
|
|||||||
touch_event_reader: EventReader<TouchInput>,
|
touch_event_reader: EventReader<TouchInput>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct Touch {
|
pub struct Touch {
|
||||||
pub id: u64,
|
pub id: u64,
|
||||||
pub start_position: Vec2,
|
pub start_position: Vec2,
|
||||||
|
pub start_force: Option<ForceTouch>,
|
||||||
pub previous_position: Vec2,
|
pub previous_position: Vec2,
|
||||||
|
pub previous_force: Option<ForceTouch>,
|
||||||
pub position: Vec2,
|
pub position: Vec2,
|
||||||
|
pub force: Option<ForceTouch>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Touch {
|
impl Touch {
|
||||||
@ -48,47 +104,69 @@ impl Touch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
impl From<&TouchInput> for Touch {
|
||||||
|
fn from(input: &TouchInput) -> Touch {
|
||||||
|
Touch {
|
||||||
|
id: input.id,
|
||||||
|
start_position: input.position,
|
||||||
|
start_force: input.force,
|
||||||
|
previous_position: input.position,
|
||||||
|
previous_force: input.force,
|
||||||
|
position: input.position,
|
||||||
|
force: input.force,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct Touches {
|
pub struct Touches {
|
||||||
active_touches: HashMap<u64, Touch>,
|
pressed: HashMap<u64, Touch>,
|
||||||
just_pressed: HashSet<u64>,
|
just_pressed: HashMap<u64, Touch>,
|
||||||
just_released: HashSet<u64>,
|
just_released: HashMap<u64, Touch>,
|
||||||
just_cancelled: HashSet<u64>,
|
just_cancelled: HashMap<u64, Touch>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Touches {
|
impl Touches {
|
||||||
pub fn iter(&self) -> impl Iterator<Item = &Touch> + '_ {
|
pub fn iter(&self) -> impl Iterator<Item = &Touch> + '_ {
|
||||||
self.active_touches.values()
|
self.pressed.values()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_pressed(&self, id: u64) -> Option<&Touch> {
|
||||||
|
self.pressed.get(&id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn just_pressed(&self, id: u64) -> bool {
|
pub fn just_pressed(&self, id: u64) -> bool {
|
||||||
self.just_pressed.contains(&id)
|
self.just_pressed.contains_key(&id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_just_pressed(&self) -> impl Iterator<Item = &Touch> + '_ {
|
pub fn iter_just_pressed(&self) -> impl Iterator<Item = &Touch> + '_ {
|
||||||
self.just_pressed
|
self.just_pressed
|
||||||
.iter()
|
.iter()
|
||||||
.map(move |id| self.active_touches.get(id).unwrap())
|
.map(move |(id, _)| self.pressed.get(id).unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_released(&self, id: u64) -> Option<&Touch> {
|
||||||
|
self.just_released.get(&id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn just_released(&self, id: u64) -> bool {
|
pub fn just_released(&self, id: u64) -> bool {
|
||||||
self.just_released.contains(&id)
|
self.just_released.contains_key(&id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_just_released(&self) -> impl Iterator<Item = &Touch> + '_ {
|
pub fn iter_just_released(&self) -> impl Iterator<Item = &Touch> + '_ {
|
||||||
self.just_released
|
self.just_released
|
||||||
.iter()
|
.iter()
|
||||||
.map(move |id| self.active_touches.get(id).unwrap())
|
.map(move |(id, _)| self.pressed.get(id).unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn just_cancelled(&self, id: u64) -> bool {
|
pub fn just_cancelled(&self, id: u64) -> bool {
|
||||||
self.just_cancelled.contains(&id)
|
self.just_cancelled.contains_key(&id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_just_cancelled(&self) -> impl Iterator<Item = &Touch> + '_ {
|
pub fn iter_just_cancelled(&self) -> impl Iterator<Item = &Touch> + '_ {
|
||||||
self.just_cancelled
|
self.just_cancelled
|
||||||
.iter()
|
.iter()
|
||||||
.map(move |id| self.active_touches.get(id).unwrap())
|
.map(move |(id, _)| self.pressed.get(id).unwrap())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,45 +176,30 @@ pub fn touch_screen_input_system(
|
|||||||
mut touch_state: ResMut<Touches>,
|
mut touch_state: ResMut<Touches>,
|
||||||
touch_input_events: Res<Events<TouchInput>>,
|
touch_input_events: Res<Events<TouchInput>>,
|
||||||
) {
|
) {
|
||||||
let touch_state = &mut *touch_state;
|
let touch_state = touch_state.deref_mut();
|
||||||
for released_id in touch_state.just_released.iter() {
|
|
||||||
touch_state.active_touches.remove(&released_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
for cancelled_id in touch_state.just_cancelled.iter() {
|
|
||||||
touch_state.active_touches.remove(&cancelled_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
touch_state.just_pressed.clear();
|
touch_state.just_pressed.clear();
|
||||||
touch_state.just_cancelled.clear();
|
touch_state.just_released.clear();
|
||||||
|
|
||||||
for event in state.touch_event_reader.iter(&touch_input_events) {
|
for event in state.touch_event_reader.iter(&touch_input_events) {
|
||||||
let active_touch = touch_state.active_touches.get(&event.id);
|
|
||||||
match event.phase {
|
match event.phase {
|
||||||
TouchPhase::Started => {
|
TouchPhase::Started => {
|
||||||
touch_state.active_touches.insert(
|
touch_state.pressed.insert(event.id, event.into());
|
||||||
event.id,
|
touch_state.just_pressed.insert(event.id, event.into());
|
||||||
Touch {
|
|
||||||
id: event.id,
|
|
||||||
start_position: event.position,
|
|
||||||
previous_position: event.position,
|
|
||||||
position: event.position,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
touch_state.just_pressed.insert(event.id);
|
|
||||||
}
|
}
|
||||||
TouchPhase::Moved => {
|
TouchPhase::Moved => {
|
||||||
let old_touch = active_touch.unwrap();
|
let mut new_touch = touch_state.pressed.get(&event.id).cloned().unwrap();
|
||||||
let mut new_touch = old_touch.clone();
|
|
||||||
new_touch.previous_position = new_touch.position;
|
new_touch.previous_position = new_touch.position;
|
||||||
|
new_touch.previous_force = new_touch.force;
|
||||||
new_touch.position = event.position;
|
new_touch.position = event.position;
|
||||||
touch_state.active_touches.insert(event.id, new_touch);
|
new_touch.force = event.force;
|
||||||
|
touch_state.pressed.insert(event.id, new_touch);
|
||||||
}
|
}
|
||||||
TouchPhase::Ended => {
|
TouchPhase::Ended => {
|
||||||
touch_state.just_released.insert(event.id);
|
touch_state.just_released.insert(event.id, event.into());
|
||||||
|
touch_state.pressed.remove_entry(&event.id);
|
||||||
}
|
}
|
||||||
TouchPhase::Cancelled => {
|
TouchPhase::Cancelled => {
|
||||||
touch_state.just_cancelled.insert(event.id);
|
touch_state.just_cancelled.insert(event.id, event.into());
|
||||||
|
touch_state.pressed.remove_entry(&event.id);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use crate::Node;
|
|||||||
use bevy_app::{EventReader, Events};
|
use bevy_app::{EventReader, Events};
|
||||||
use bevy_core::FloatOrd;
|
use bevy_core::FloatOrd;
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_input::{mouse::MouseButton, Input};
|
use bevy_input::{mouse::MouseButton, touch::Touches, Input};
|
||||||
use bevy_math::Vec2;
|
use bevy_math::Vec2;
|
||||||
use bevy_transform::components::GlobalTransform;
|
use bevy_transform::components::GlobalTransform;
|
||||||
use bevy_window::CursorMoved;
|
use bevy_window::CursorMoved;
|
||||||
@ -43,6 +43,7 @@ pub fn ui_focus_system(
|
|||||||
mut state: Local<State>,
|
mut state: Local<State>,
|
||||||
mouse_button_input: Res<Input<MouseButton>>,
|
mouse_button_input: Res<Input<MouseButton>>,
|
||||||
cursor_moved_events: Res<Events<CursorMoved>>,
|
cursor_moved_events: Res<Events<CursorMoved>>,
|
||||||
|
touches_input: Res<Touches>,
|
||||||
mut node_query: Query<(
|
mut node_query: Query<(
|
||||||
Entity,
|
Entity,
|
||||||
&Node,
|
&Node,
|
||||||
@ -54,8 +55,11 @@ pub fn ui_focus_system(
|
|||||||
if let Some(cursor_moved) = state.cursor_moved_event_reader.latest(&cursor_moved_events) {
|
if let Some(cursor_moved) = state.cursor_moved_event_reader.latest(&cursor_moved_events) {
|
||||||
state.cursor_position = cursor_moved.position;
|
state.cursor_position = cursor_moved.position;
|
||||||
}
|
}
|
||||||
|
if let Some(touch) = touches_input.get_pressed(0) {
|
||||||
|
state.cursor_position = touch.position;
|
||||||
|
}
|
||||||
|
|
||||||
if mouse_button_input.just_released(MouseButton::Left) {
|
if mouse_button_input.just_released(MouseButton::Left) || touches_input.just_released(0) {
|
||||||
for (_entity, _node, _global_transform, interaction, _focus_policy) in node_query.iter_mut()
|
for (_entity, _node, _global_transform, interaction, _focus_policy) in node_query.iter_mut()
|
||||||
{
|
{
|
||||||
if let Some(mut interaction) = interaction {
|
if let Some(mut interaction) = interaction {
|
||||||
@ -66,7 +70,8 @@ pub fn ui_focus_system(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mouse_clicked = mouse_button_input.just_pressed(MouseButton::Left);
|
let mouse_clicked =
|
||||||
|
mouse_button_input.just_pressed(MouseButton::Left) || touches_input.just_released(0);
|
||||||
let mut hovered_entity = None;
|
let mut hovered_entity = None;
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use bevy_input::{
|
use bevy_input::{
|
||||||
keyboard::{KeyCode, KeyboardInput},
|
keyboard::{KeyCode, KeyboardInput},
|
||||||
mouse::MouseButton,
|
mouse::MouseButton,
|
||||||
touch::{TouchInput, TouchPhase},
|
touch::{ForceTouch, TouchInput, TouchPhase},
|
||||||
ElementState,
|
ElementState,
|
||||||
};
|
};
|
||||||
use bevy_math::Vec2;
|
use bevy_math::Vec2;
|
||||||
@ -39,6 +39,18 @@ pub fn convert_touch_input(touch_input: winit::event::Touch) -> TouchInput {
|
|||||||
winit::event::TouchPhase::Cancelled => TouchPhase::Cancelled,
|
winit::event::TouchPhase::Cancelled => TouchPhase::Cancelled,
|
||||||
},
|
},
|
||||||
position: Vec2::new(touch_input.location.x as f32, touch_input.location.y as f32),
|
position: Vec2::new(touch_input.location.x as f32, touch_input.location.y as f32),
|
||||||
|
force: touch_input.force.map(|f| match f {
|
||||||
|
winit::event::Force::Calibrated {
|
||||||
|
force,
|
||||||
|
max_possible_force,
|
||||||
|
altitude_angle,
|
||||||
|
} => ForceTouch::Calibrated {
|
||||||
|
force,
|
||||||
|
max_possible_force,
|
||||||
|
altitude_angle,
|
||||||
|
},
|
||||||
|
winit::event::Force::Normalized(x) => ForceTouch::Normalized(x),
|
||||||
|
}),
|
||||||
id: touch_input.id,
|
id: touch_input.id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -261,9 +261,15 @@ pub fn winit_runner(mut app: App) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
WindowEvent::Touch(touch) => {
|
WindowEvent::Touch(mut touch) => {
|
||||||
let mut touch_input_events =
|
let mut touch_input_events =
|
||||||
app.resources.get_mut::<Events<TouchInput>>().unwrap();
|
app.resources.get_mut::<Events<TouchInput>>().unwrap();
|
||||||
|
let windows = app.resources.get_mut::<Windows>().unwrap();
|
||||||
|
// FIXME?: On Android window start is top while on PC/Linux/OSX on bottom
|
||||||
|
if cfg!(target_os = "android") {
|
||||||
|
let window_height = windows.get_primary().unwrap().height();
|
||||||
|
touch.location.y = window_height as f64 - touch.location.y;
|
||||||
|
}
|
||||||
touch_input_events.send(converters::convert_touch_input(touch));
|
touch_input_events.send(converters::convert_touch_input(touch));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
These examples demonstrate the main features of Bevy and how to use them.
|
These examples demonstrate the main features of Bevy and how to use them.
|
||||||
To run an example, use the command `cargo run --example <Example>`, and add the option `--features x11` or `--features wayland` to force the example to run on a specific window compositor, e.g.
|
To run an example, use the command `cargo run --example <Example>`, and add the option `--features x11` or `--features wayland` to force the example to run on a specific window compositor, e.g.
|
||||||
```
|
|
||||||
|
```sh
|
||||||
cargo run --features wayland --example hello_world
|
cargo run --features wayland --example hello_world
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -119,47 +120,61 @@ Example | File | Description
|
|||||||
|
|
||||||
## WASM
|
## WASM
|
||||||
|
|
||||||
#### pre-req
|
#### Pre-requirements
|
||||||
|
|
||||||
$ rustup target add wasm32-unknown-unknown
|
```sh
|
||||||
$ cargo install wasm-bindgen-cli
|
rustup target add wasm32-unknown-unknown
|
||||||
|
cargo install wasm-bindgen-cli
|
||||||
|
```
|
||||||
|
|
||||||
#### build & run
|
#### Build & run
|
||||||
|
|
||||||
Following is an example for `headless_wasm`. For other examples in wasm/ directory,
|
Following is an example for `headless_wasm`. For other examples in wasm/ directory,
|
||||||
change the `headless_wasm` in the following commands **and edit** `examples/wasm/index.html`
|
change the `headless_wasm` in the following commands **and edit** `examples/wasm/index.html`
|
||||||
to point to the correct `.js` file.
|
to point to the correct `.js` file.
|
||||||
|
|
||||||
$ cargo build --example headless_wasm --target wasm32-unknown-unknown --no-default-features
|
```sh
|
||||||
$ wasm-bindgen --out-dir examples/wasm/target --target web target/wasm32-unknown-unknown/debug/examples/headless_wasm.wasm
|
cargo build --example headless_wasm --target wasm32-unknown-unknown --no-default-features
|
||||||
|
wasm-bindgen --out-dir examples/wasm/target --target web target/wasm32-unknown-unknown/debug/examples/headless_wasm.wasm
|
||||||
|
```
|
||||||
|
|
||||||
Then serve `examples/wasm` dir to browser. i.e.
|
Then serve `examples/wasm` dir to browser. i.e.
|
||||||
|
|
||||||
$ basic-http-server examples/wasm
|
```sh
|
||||||
|
basic-http-server examples/wasm
|
||||||
|
```
|
||||||
|
|
||||||
## iOS
|
## iOS
|
||||||
|
|
||||||
#### pre-req
|
#### Pre-requirements
|
||||||
|
|
||||||
$ rustup target add aarch64-apple-ios x86_64-apple-ios
|
```sh
|
||||||
$ cargo install cargo-lipo
|
rustup target add aarch64-apple-ios x86_64-apple-ios
|
||||||
|
cargo install cargo-lipo
|
||||||
|
```
|
||||||
|
|
||||||
#### build & run
|
#### Build & run
|
||||||
|
|
||||||
Using bash:
|
Using bash:
|
||||||
|
|
||||||
$ cd examples/ios
|
```sh
|
||||||
$ make run
|
cd examples/ios
|
||||||
|
make run
|
||||||
|
```
|
||||||
|
|
||||||
In an ideal world, this will boot up, install and run the app for the first
|
In an ideal world, this will boot up, install and run the app for the first
|
||||||
iOS simulator in your `xcrun simctl devices list`. If this fails, you can
|
iOS simulator in your `xcrun simctl devices list`. If this fails, you can
|
||||||
specify the simulator device UUID via:
|
specify the simulator device UUID via:
|
||||||
|
|
||||||
$ DEVICE_ID=${YOUR_DEVICE_ID} make run
|
```sh
|
||||||
|
DEVICE_ID=${YOUR_DEVICE_ID} make run
|
||||||
|
```
|
||||||
|
|
||||||
If you'd like to see xcode do stuff, you can run
|
If you'd like to see xcode do stuff, you can run
|
||||||
|
|
||||||
$ open bevy_ios_example.xcodeproj/
|
```sh
|
||||||
|
open bevy_ios_example.xcodeproj/
|
||||||
|
```
|
||||||
|
|
||||||
which will open xcode. You then must push the zoom zoom play button and wait
|
which will open xcode. You then must push the zoom zoom play button and wait
|
||||||
for the magic.
|
for the magic.
|
||||||
@ -175,42 +190,46 @@ used for the `Makefile`.
|
|||||||
|
|
||||||
## Android
|
## Android
|
||||||
|
|
||||||
#### pre-req
|
#### Pre-requirements
|
||||||
|
|
||||||
$ rustup target add aarch64-linux-android armv7-linux-androideabi
|
```sh
|
||||||
$ cargo install cargo-apk
|
rustup target add aarch64-linux-android armv7-linux-androideabi
|
||||||
|
cargo install cargo-apk
|
||||||
|
```
|
||||||
|
|
||||||
The Android SDK 29 must be installed, and the environment variable `ANDROID_SDK_ROOT` set to the root Android `sdk` folder.
|
The Android SDK must be installed, and the environment variable `ANDROID_SDK_ROOT` set to the root Android `sdk` folder.
|
||||||
|
|
||||||
When using `NDK (Side by side)`, the environment variable `ANDROID_NDK_ROOT` must also be set to one of the NDKs in `sdk\ndk\[NDK number]`.
|
When using `NDK (Side by side)`, the environment variable `ANDROID_NDK_ROOT` must also be set to one of the NDKs in `sdk\ndk\[NDK number]`.
|
||||||
|
|
||||||
#### build & run
|
#### Build & run
|
||||||
|
|
||||||
To run on a device setup for Android development, run:
|
To run on a device setup for Android development, run:
|
||||||
|
|
||||||
$ cargo apk run --example bevy_android --features="supported_android_features" --no-default-features
|
```sh
|
||||||
|
cargo apk run --example bevy_android
|
||||||
|
```
|
||||||
|
|
||||||
:warning: At this time Bevy does not work in Android Emulator.
|
:warning: At this time Bevy does not work in Android Emulator.
|
||||||
|
|
||||||
When using Bevy as a library, the following fields must be added to `Cargo.toml`:
|
When using Bevy as a library, the following fields must be added to `Cargo.toml`:
|
||||||
|
|
||||||
[package.metadata.android]
|
```toml
|
||||||
build_targets = [ "aarch64-linux-android", "armv7-linux-androideabi" ]
|
[package.metadata.android]
|
||||||
target_sdk_version = 29
|
build_targets = ["aarch64-linux-android", "armv7-linux-androideabi"]
|
||||||
min_sdk_version = 29
|
target_sdk_version = 29
|
||||||
|
min_sdk_version = 16
|
||||||
[[package.metadata.android.feature]]
|
```
|
||||||
name = "android.hardware.vulkan.level"
|
|
||||||
version = "1"
|
|
||||||
|
|
||||||
Please reference `cargo-apk` [README](https://crates.io/crates/cargo-apk) for other Android Manifest fields.
|
Please reference `cargo-apk` [README](https://crates.io/crates/cargo-apk) for other Android Manifest fields.
|
||||||
|
|
||||||
#### old phones
|
#### Old phones
|
||||||
|
|
||||||
Bevy by default requires Android API level 29 which is the [Play Store's minimum API to upload or update apps](https://developer.android.com/distribute/best-practices/develop/target-sdk). Users of older phones may want to use an older API when testing.
|
Bevy by default targets Android API level 29 in its examples which is the [Play Store's minimum API to upload or update apps](https://developer.android.com/distribute/best-practices/develop/target-sdk). Users of older phones may want to use an older API when testing.
|
||||||
|
|
||||||
To use a different API, the following fields must be updated in Cargo.toml:
|
To use a different API, the following fields must be updated in Cargo.toml:
|
||||||
|
|
||||||
[package.metadata.android]
|
```toml
|
||||||
target_sdk_version = >>API<<
|
[package.metadata.android]
|
||||||
min_sdk_version = >>API or less<<
|
target_sdk_version = >>API<<
|
||||||
|
min_sdk_version = >>API or less<<
|
||||||
|
```
|
||||||
|
Loading…
Reference in New Issue
Block a user