Embed assets in elf file (#2466)
* FBT: file_assets generator * Elf file: process manifest section externally * FBT, file_assets generator: add assets signature * Storage: assets path alias * Flipper application: assets unpacker * Apps, Storage: use '/data' alias for apps data * Storage: copy file to file * Assets: log flag, fixes * Update f18 api * Assets: asserts * Assets: fix signature_data check * App assets: example * Example assets: fix folder structure in readme * Assets: fix error handling * Assets builder: use ansii instead of utf-8, use .fapassets section instead of .fapfiles, add assets path to signature * Elf file: comment strange places * Storage: totaly optimized storage_file_copy_to_file
This commit is contained in:
58
applications/examples/example_apps_assets/README.md
Normal file
58
applications/examples/example_apps_assets/README.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# Apps Assets folder Example
|
||||
|
||||
This example shows how to use the Apps Assets folder to store data that is not part of the application itself, but is required for its operation, and that data is provided with the application.
|
||||
|
||||
## What is the Apps Assets Folder?
|
||||
|
||||
The **Apps Assets** folder is a folder where external applications unpack their assets.
|
||||
|
||||
The path to the current application folder is related to the `appid` of the app. The `appid` is used to identify the app in the app store and is stored in the `application.fam` file.
|
||||
The Apps Assets folder is located only on the external storage, the SD card.
|
||||
|
||||
For example, if the `appid` of the app is `snake_game`, the path to the Apps Assets folder will be `/ext/apps_assets/snake_game`. But using raw paths is not recommended, because the path to the Apps Assets folder can change in the future. Use the `/assets` alias instead.
|
||||
|
||||
## How to get the path to the Apps Assets folder?
|
||||
|
||||
You can use `/assets` alias to get the path to the current application data folder. For example, if you want to open a file `database.txt` in the Apps Assets folder, you can use the next path: `/data/database.txt`. But this way is not recommended, because even the `/assets` alias can change in the future.
|
||||
|
||||
We recommend to use the `APP_ASSETS_PATH` macro to get the path to the Apps Assets folder. For example, if you want to open a file `database.txt` in the Apps Assets folder, you can use the next path: `APP_ASSETS_PATH("database.txt")`.
|
||||
|
||||
## What is the difference between the Apps Assets folder and the Apps Data folder?
|
||||
|
||||
The Apps Assets folder is used to store the data <u>provided</u> with the application. For example, if you want to create a game, you can store game levels (contant data) in the Apps Assets folder.
|
||||
|
||||
The Apps Data folder is used to store data <u>generated</u> by the application. For example, if you want to create a game, you can save the progress of the game (user-generated data) in the Apps Data folder.
|
||||
|
||||
## How to provide the data with the app?
|
||||
|
||||
To provide data with an application, you need to create a folder inside your application folder (eg "files") and place the data in it. After that, you need to add `fap_file_assets="files"` to your application.fam file.
|
||||
|
||||
For example, if you want to provide game levels with the application, you need to create a "levels" folder inside the "files" folder and put the game levels in it. After that, you need to add `fap_file_assets="files"` to your application.fam file. The final application folder structure will look like this:
|
||||
|
||||
```
|
||||
snake_game
|
||||
├── application.fam
|
||||
├── snake_game.c
|
||||
└── files
|
||||
└── levels
|
||||
├── level1.txt
|
||||
├── level2.txt
|
||||
└── level3.txt
|
||||
```
|
||||
|
||||
When app is launched, the `files` folder will be unpacked to the Apps Assets folder. The final structure of the Apps Assets folder will look like this:
|
||||
|
||||
```
|
||||
/assets
|
||||
├── .assets.signature
|
||||
└── levels
|
||||
├── level1.txt
|
||||
├── level2.txt
|
||||
└── level3.txt
|
||||
```
|
||||
|
||||
## When will the data be unpacked?
|
||||
|
||||
The data is unpacked when the application starts, if the application is launched for the first time, or if the data within the application is updated.
|
||||
|
||||
When an application is compiled, the contents of the "files" folder are hashed and stored within the application itself. When the application starts, this hash is compared to the hash stored in the `.assets.signature` file. If the hashes differ or the `.assets.signature` file does not exist, the application folder is deleted and the new data is unpacked.
|
10
applications/examples/example_apps_assets/application.fam
Normal file
10
applications/examples/example_apps_assets/application.fam
Normal file
@@ -0,0 +1,10 @@
|
||||
App(
|
||||
appid="example_apps_assets",
|
||||
name="Example: Apps Assets",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="example_apps_assets_main",
|
||||
requires=["gui"],
|
||||
stack_size=4 * 1024,
|
||||
fap_category="Examples",
|
||||
fap_file_assets="files",
|
||||
)
|
@@ -0,0 +1,48 @@
|
||||
#include <furi.h>
|
||||
#include <storage/storage.h>
|
||||
#include <toolbox/stream/stream.h>
|
||||
#include <toolbox/stream/file_stream.h>
|
||||
|
||||
// Define log tag
|
||||
#define TAG "example_apps_assets"
|
||||
|
||||
static void example_apps_data_print_file_content(Storage* storage, const char* path) {
|
||||
Stream* stream = file_stream_alloc(storage);
|
||||
FuriString* line = furi_string_alloc();
|
||||
|
||||
FURI_LOG_I(TAG, "----------------------------------------");
|
||||
FURI_LOG_I(TAG, "File \"%s\" content:", path);
|
||||
if(file_stream_open(stream, path, FSAM_READ, FSOM_OPEN_EXISTING)) {
|
||||
while(stream_read_line(stream, line)) {
|
||||
furi_string_replace_all(line, "\r", "");
|
||||
furi_string_replace_all(line, "\n", "");
|
||||
FURI_LOG_I(TAG, "%s", furi_string_get_cstr(line));
|
||||
}
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Failed to open file");
|
||||
}
|
||||
FURI_LOG_I(TAG, "----------------------------------------");
|
||||
|
||||
furi_string_free(line);
|
||||
file_stream_close(stream);
|
||||
stream_free(stream);
|
||||
}
|
||||
|
||||
// Application entry point
|
||||
int32_t example_apps_assets_main(void* p) {
|
||||
// Mark argument as unused
|
||||
UNUSED(p);
|
||||
|
||||
// Open storage
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
|
||||
example_apps_data_print_file_content(storage, APP_ASSETS_PATH("test_asset.txt"));
|
||||
example_apps_data_print_file_content(storage, APP_ASSETS_PATH("poems/a jelly-fish.txt"));
|
||||
example_apps_data_print_file_content(storage, APP_ASSETS_PATH("poems/theme in yellow.txt"));
|
||||
example_apps_data_print_file_content(storage, APP_ASSETS_PATH("poems/my shadow.txt"));
|
||||
|
||||
// Close storage
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
return 0;
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
A Jelly-Fish by Marianne Moore
|
||||
|
||||
Visible, invisible,
|
||||
A fluctuating charm,
|
||||
An amber-colored amethyst
|
||||
Inhabits it; your arm
|
||||
Approaches, and
|
||||
It opens and
|
||||
It closes;
|
||||
You have meant
|
||||
To catch it,
|
||||
And it shrivels;
|
||||
You abandon
|
||||
Your intent—
|
||||
It opens, and it
|
||||
Closes and you
|
||||
Reach for it—
|
||||
The blue
|
||||
Surrounding it
|
||||
Grows cloudy, and
|
||||
It floats away
|
||||
From you.
|
||||
|
||||
source: "https://poets.org/anthology/poems-your-poetry-project-public-domain"
|
@@ -0,0 +1,23 @@
|
||||
My Shadow by Robert Louis Stevenson
|
||||
|
||||
I have a little shadow that goes in and out with me,
|
||||
And what can be the use of him is more than I can see.
|
||||
He is very, very like me from the heels up to the head;
|
||||
And I see him jump before me, when I jump into my bed.
|
||||
|
||||
The funniest thing about him is the way he likes to grow—
|
||||
Not at all like proper children, which is always very slow;
|
||||
For he sometimes shoots up taller like an India-rubber ball,
|
||||
And he sometimes gets so little that there’s none of him at all.
|
||||
|
||||
He hasn’t got a notion of how children ought to play,
|
||||
And can only make a fool of me in every sort of way.
|
||||
He stays so close beside me, he’s a coward you can see;
|
||||
I’d think shame to stick to nursie as that shadow sticks to me!
|
||||
|
||||
One morning, very early, before the sun was up,
|
||||
I rose and found the shining dew on every buttercup;
|
||||
But my lazy little shadow, like an arrant sleepy-head,
|
||||
Had stayed at home behind me and was fast asleep in bed.
|
||||
|
||||
source: "https://poets.org/anthology/poems-your-poetry-project-public-domain"
|
@@ -0,0 +1,19 @@
|
||||
Theme in Yellow by Carl Sandburg
|
||||
|
||||
I spot the hills
|
||||
With yellow balls in autumn.
|
||||
I light the prairie cornfields
|
||||
Orange and tawny gold clusters
|
||||
And I am called pumpkins.
|
||||
On the last of October
|
||||
When dusk is fallen
|
||||
Children join hands
|
||||
And circle round me
|
||||
Singing ghost songs
|
||||
And love to the harvest moon;
|
||||
I am a jack-o'-lantern
|
||||
With terrible teeth
|
||||
And the children know
|
||||
I am fooling.
|
||||
|
||||
source: "https://poets.org/anthology/poems-your-poetry-project-public-domain"
|
@@ -0,0 +1 @@
|
||||
## This is test file content
|
@@ -9,10 +9,16 @@ The **Apps Data** folder is a folder used to store data for external apps that a
|
||||
The path to the current application folder is related to the `appid` of the app. The `appid` is used to identify the app in the app store and is stored in the `application.fam` file.
|
||||
The Apps Data folder is located only on the external storage, the SD card.
|
||||
|
||||
For example, if the `appid` of the app is `snake_game`, the path to the Apps Data folder will be `/ext/apps_data/snake_game`. But using raw paths is not recommended, because the path to the Apps Data folder can change in the future. Use the `/app` alias instead.
|
||||
For example, if the `appid` of the app is `snake_game`, the path to the Apps Data folder will be `/ext/apps_data/snake_game`. But using raw paths is not recommended, because the path to the Apps Data folder can change in the future. Use the `/data` alias instead.
|
||||
|
||||
## How to get the path to the Apps Data folder?
|
||||
|
||||
You can use `/app` alias to get the path to the current application data folder. For example, if you want to open a file `config.txt` in the Apps Data folder, you can use the next path: `/app/config.txt`. But this way is not recommended, because even the `/app` alias can change in the future.
|
||||
You can use `/data` alias to get the path to the current application data folder. For example, if you want to open a file `config.txt` in the Apps Data folder, you can use the next path: `/data/config.txt`. But this way is not recommended, because even the `/data` alias can change in the future.
|
||||
|
||||
We recommend to use the `APP_DATA_PATH` macro to get the path to the Apps Data folder. For example, if you want to open a file `config.txt` in the Apps Data folder, you can use the next path: `APP_DATA_PATH("config.txt")`.
|
||||
We recommend to use the `APP_DATA_PATH` macro to get the path to the Apps Data folder. For example, if you want to open a file `config.txt` in the Apps Data folder, you can use the next path: `APP_DATA_PATH("config.txt")`.
|
||||
|
||||
## What is the difference between the Apps Assets folder and the Apps Data folder?
|
||||
|
||||
The Apps Assets folder is used to store the data <u>provided</u> with the application. For example, if you want to create a game, you can store game levels (contant data) in the Apps Assets folder.
|
||||
|
||||
The Apps Data folder is used to store data <u>generated</u> by the application. For example, if you want to create a game, you can save the progress of the game (user-generated data) in the Apps Data folder.
|
Reference in New Issue
Block a user