Skip to content

Usage CreatingPackages

marchbold edited this page Jun 22, 2023 · 9 revisions

Creating a package

To create a package use the create command to construct a basic template:

apm create

You can specify a subdirectory to be used to keep content in a subdirectory if required:

apm create packageFolder

This will ask a few questions (package name, identifier, version etc) and will create something similar to the following structure populated with the data:

|____ package.json
|____ README.md
|____ ane
|____ swc
|____ src
|____ assets
|____ platforms

Setting properties

Open up the package.json file in a text editor. It is important that you set the following properties:

  • identifier: The identifier for the package;
  • name: The name of the package;
  • description: A valid description of the package;
  • type: Must be one of the supported types, ane, swc or src;
  • version: SemVer version for this version of the package;
  • sourceUrl: A url for downloading this version of the package,

The source url can be any location you specify. We suggest using github releases and adding this package zip as a release asset. The url would then be of the form:

https://github.com/ORGANISATION/REPOSITORY/releases/download/VERSION/IDENTIFIER_VERSION.airpackage

For example, for distriqt's Core ANE version 6.4.1:

https://github.com/distriqt/ANE-Core/releases/download/v6.4.001/com.distriqt.Core_6.4.1.airpackage

This allows you to publish your packages alongside your package code.

Identifier

The identifier should start with a reversed Internet domain name and end with the title of the package. For ANE's we suggest using the same identifier as the extension id. The rules here are similar to a java package name.

  • You can use alpha numeric characters, the period character and the underscore character;
  • Do not start a word with a number (eg com.a123.test is valid, but com.123a.test should be avoided);
  • Do not use a hyphen or other special characters (except for variants as below);

Examples:

  • com.distriqt.Adverts
  • starling
  • google.gson
  • androidx.core

Variants

You may have multiple variants of your package each which have the same API but differ in some way. For example, you may provide your package as a SWC and as source code. These would be 2 variants of the same library.

You indicate a variant by adding a hyphen - followed by the variant name. For example, com.example.package is a main package identifier and com.example.package-variant is a variant.

If we use starling as an example, the main Starling package is a swc package with the identifier starling, but there is also a source version available with the identifier starling-source. This is a variant of the package.

These packages will conflict, so only one will be installed for the user. Generally the default starling package will be used in dependency cases, unless the user specifically installs the starling-source package for their project.

Notes:

  • only one variant of a package can be installed at a time in a project;
  • if the user specifically installs a version, then other versions installed as dependencies will be removed;

Examples:

  • Adverts

    • com.distriqt.Adverts - contains the Admob implementation;
    • com.distriqt.Adverts-huawei - contains the Huawei Ads implementation;
  • Starling

    • starling - contains the starling swc library;
    • starling-source - contains the starling source;

Status

You can set a status for your package version which will determine how it gets shown in searches by apm.

The current values are:

Value Description
release (default) a normal released version available to be installed and appears in any searches
prerelease a pre-release version for testing, this will only be appear to users who add the --include-prerelease flag to install/search/view commands
discontinued use this when you no longer wish to maintain a package, it will no longer appear in searches but will still install for users who previously installed it

Dependencies

To add a dependency on another package, add a line to the dependencies array. The simplest way is to format a string in the format PACKAGEIDENTIFIER:VERSION, eg:

    "dependencies": [
        "com.package.dependency.a:1.0.0"
    ],

You can repeat this to add multiple dependencies:

    "dependencies": [
        "com.package.dependency.a:1.0.0",
        "com.package.dependency.b:1.2.0",
        "com.package.dependency.c:4.0.0"
    ],

If you wish you can also add a dependency defined as an object:

    "dependencies": [
        {
            "id": "com.package.dependency.a",
            "version": "1.0.0"
        }
    ],

both these formats are equivalent and can be mixed:

    "dependencies": [
        {
            "id": "com.package.dependency.a",
            "version": "1.0.0"
        },
        "com.package.dependency.b:1.2.0",
        "com.package.dependency.c:4.0.0"
    ],

Dependency Versions

You can specify a specific version of a package as a dependency or you can specify a "version range". Specifying a "version range" allows your package to specify which updates to accept from dependencies. This is important if there are patches or updates to a dependency that you would like to allow for without having to publish a new package.

For example to accept patch releases to a dependency package you can specify the following:

    "dependencies": [
        {
            "id": "com.package.dependency.a",
            "version": "1.0.x"
        }
    ],

For more details on acceptable values for version ranges see the documentation on Versioning.

You can also use apm to add the latest version of a dependency:

apm package add com.package.dependency.a

This will attempt to locate the package in the repository and determine the latest version.

Configuration Parameters

Optional

If your extension requires any configuration variables (eg for manifest or info addition substitutions) you should add them to the parameters. This is an array of configuration parameter names that your extension uses, and can include optional fields:

  • whether the parameter is required;
  • a defaultValue;
  • a description;

These should be named exactly as you use them in the manifest/additions for correct substitution, including case. They can either be a simple string with the parameter name, or an object containing the parameter fields:

    "parameters": [
        "packageParam",
        {
            "name": "otherRequiredParam",
            "required": "true",
            "defaultValue": "A default value for the param",
            "description": "A description for the parameter displayed when the user asks for a description of a param"
        }
    ],

We highly recommend providing a defaultValue, this is important to facilitate easy installation of a package without requiring the user to populate configuration values. Obviously certain values will require configuration such as service identifiers, however wherever possible you should provide functional default values.

If you specify the parameter is required then operations such as generating the application descriptor will fail if the parameter is not set. This is important for things like service identifiers.

The description field is a description of the parameter. This will help your users correctly set the value for the parameter. You can include links to documentation or any information that will help a user understand the usage of the parameter. The descriptions are displayed with the apm project config describe command.

Tags

Providing tags for your package allows you to tag key features of your package, and will be used to improve the visibility of your package in the repository. You should just specify tags for the key aspects of your package to ensure it appears in appropriate search results.

You specify tags as an array of strings in the package json file, for example:

"tags": [ "advertising", "app-tracking-transparency", "identifier", "idfa" ]

Or you can use apm in your package directory:

apm package set tags advertising,app-tracking-transparency,identifier,idfa

Platforms

Optional

You can specify the platforms that this package supports. By default a package is expected to support all platforms (even if it's via a default fallback library), however you can set a specific set of platforms that the package supports. This allows a user to only deploy this package to applications that are supporting the specific platform.

You specify platforms as an array of strings in the package json file, for example:

"platforms": ["android", "ios"]

Or you can use apm in your package directory:

apm package set platforms android,ios

As an example, packages like the androidx.* packages, that are only required in android projects, will have this value set to "platforms": ["android"] and hence will only be deployed when Android is part of the developer's project.

Supported platform names include:

  • ios
  • android
  • macos
  • windows
  • linux

License

Optional

You can specify a license associated with this extension and whether the access to the extension requires some private authentication or purchase.

For example you can specify a public MIT license via something like:

"purchaseUrl": "",
"license": {
    "type": "MIT",
    "url": "https://opensource.org/licenses/MIT",
    "public": true
},

This means the package is publicly available and requires no authentication and is governed by the MIT license as linked in the url.

The purchaseUrl is a property that you can set which will be made available for private packages.

"purchaseUrl": "https://airnativeextensions.com/extension/com.distriqt.Application",
"license": {
    "type": "airnativeextensions",
    "url": "https://airnativeextensions.com/license",
    "public": false
},

In this case the package is marked as private and requires authentication. The details of the license are available at the url and the purchaseUrl will be presented to the user to obtain a license in certain circumstances.

Assets

Optional

You can add assets to a directory named assets. These are static assets that a user should add into their project, such as text files or images. Generally we advise against using this mechanism but there are times when it is required.

These are often platform specific so the assets folder should contain sub-folders for each of the required platforms, eg for iOS and Android:

assets
|____ common
  |____ some_required_file_for_all_platforms.ext
|____ ios
  |____ some_ios_required_file.ext
|____ android
  |____ some_android_required_file.ext

The assets folder will be deployed into the user's application directory and the user is instructed to add these directories to their builds in the IDE usage documentation.

Supported platform directory names:

  • common
  • ios
  • android
  • macos
  • windows

Platform Specific Additions

Optional

Commonly when developing native extensions you have additions to the application descriptor that are required for specific platforms, such as manifest additions for Android and info additions / entitlements for iOS.

To deal with this you can provide specific files in your package that will be used during a merge process to construct an application descriptor for the user's application.

These files are placed in a series of folders within the platforms folder. The files must be named exactly as per the documentation below and you must structure their contents to match the expected format.

platforms
|____macos
|____ios
| |____Entitlements.xml
| |____InfoAdditions.xml
|____android
| |____AndroidManifest.xml
|____windows

Supported platform directory names:

  • ios
  • android
  • macos
  • windows

Android

On Android you can provide an AndroidManifest.xml file which will be run through a manifest merge process with all the other packages used by an application before being used to build an application descriptor.

<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.extension" >

    <uses-sdk android:minSdkVersion="19" />

    <application>
    </application>

</manifest>

You can add any specific requirements your extension requires to this file, such as permissions, activities, services etc.

Note: Do not add manifest entries required for dependency libraries. You may have had these in your documentation for your extension, but they aren't required here as they should be included with the dependency library. Just add the manifest entries specific to your extension.

You can use your configuration parameters in the manifest by surrounding the parameter name with ${} eg, ${PARAMETER}, you must match the name exactly, including case. There are also some default ones that will be generated for you such as:

  • ${applicationId}: Inserts the application android package name (eg air.com.example.app)

Example:

<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.distriqt.extension.cameraui" >

    <uses-sdk android:minSdkVersion="19" />

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

    <application android:hardwareAccelerated="true">

        <provider
            android:name="com.distriqt.extension.cameraui.content.FileProvider"
            android:authorities="${applicationId}.camerauifileprovider"
            android:grantUriPermissions="true"
            android:exported="false">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/distriqt_cameraui_paths" />
        </provider>

        <activity   android:name="com.distriqt.extension.cameraui.permissions.AuthorisationActivity"
                    android:theme="@android:style/Theme.Translucent.NoTitleBar" />

    </application>

</manifest>

iOS

On iOS you can provide an InfoAdditions.xml file and an Entitlements.xml file. These files are xml files, following the "plist" structure:

InfoAdditions.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>

    <!-- Add your info additions here -->

</dict>
</plist>

Entitlements.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>

    <!-- Add your entitlements here -->

</dict>
</plist>

You can use your configuration parameters in the manifest by surrounding the parameter name with ${} eg, ${PARAMETER}, you must match the name exactly, including case.

Example InfoAdditions.xml using several parameters for the usage descriptions:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>

    <key>NSCameraUsageDescription</key>
    <string>${cameraUsageDescription}</string>

    <key>NSMicrophoneUsageDescription</key>
    <string>${microphoneUsageDescription}</string>

    <key>NSPhotoLibraryUsageDescription</key>
    <string>${photoLibraryUsageDescription}</string>

    <key>NSPhotoLibraryAddUsageDescription</key>
    <string>${photoLibraryAddUsageDescription}</string>

</dict>
</plist>

Note: For the usage description and similar tags we have introduced the convention of using the name of the key, removing the "NS" prefix and starting with a lower case character. For example in the above the NSCameraUsageDescription value is cameraUsageDescription. We suggest you follow this convention for any standard iOS / macOS values.

Building a package

Building is the process of constructing a package of your content.

Once you have completed placing your content in the structure you can use the build command to construct the package.

apm build

(or use the folder name if you have if in a subdirectory apm build packageFolder)

This will output the critical information from the package. verify the content and then construct a airpackage file which you can publish. The airpackage file is just a zip file but named for easy identification.

For example:

$ apm build idfa
Building package
- identifier:  com.distriqt.IDFA
- name:        IDFA
- description: The IDFA extension gives you simple access to the advertising identifiers on Android and iOS.
- type:        ane
- tags:        advertising,app-tracking-transparency,identifier,idfa
- version:     5.0.29
- status:      prerelease
- publishedAt: 2021-09-30T00:00:00.000Z
- sourceUrl:   https://github.com/distriqt/ANE-IDFA/releases/download/v5.0.029/com.distriqt.IDFA_5.0.29.airpackage
✓ Package content verified
✓ Package built: com.distriqt.IDFA_5.0.29.airpackage

Publishing

Publishing is the process of listing your package in the AIR package repository.

Please note there is no way to "unpublish" a package. As once published a package can be used by other developers, unpublishing a package can have repercussions on many developers. If you wish to unpublish a package contact the repository administrators and they will review the package.

We suggest that you make sure the information output from the build is correct and test by installing the package locally in an application before publishing.

If you no longer plan to maintain a package you can mark the versions as "discontinued" and they will no longer appear in searches. See status for more information.

In order to do this you must firstly you must upload the airpackage package to your sourceUrl destination. Publishing will fail if this is not available.

Then call apm publish passing the name of the package you built previously.

apm publish <your.airpackage>

This process will again verify the content, verify the sourceUrl is accessible, generate a checksum of the file and then check the specified dependencies are available in the repository.

Once this has been completed successfully the package will be listed in the repository.

For example:

$ apm publish com.distriqt.IDFA_5.0.29.airpackage
Publishing package: com.distriqt.IDFA_5.0.29.airpackage
✓ Extracted zip
- identifier:  com.distriqt.IDFA
- name:        IDFA
- description: The IDFA extension gives you simple access to the advertising identifiers on Android and iOS.
- type:        ane
- tags:        advertising,android,app-tracking-transparency,identifier,idfa,ios
- version:     5.0.29
- status:      prerelease
- publishedAt: 2021-09-30T00:00:00.000Z
- sourceUrl:   https://github.com/distriqt/ANE-IDFA/releases/download/v5.0.029/com.distriqt.IDFA_5.0.29.airpackage
✓ Package content verified
✓ Package definition file loaded
✓ Generated checksum: 2f3e7fd0e8a5238178f244211bf6d7ff58dfdb8e5c5df1a27f7d2561439da8db
✓ Package content verified
✓ Dependency VERIFIED: androidx.core@1.5.0
✓ Dependency VERIFIED: com.distriqt.Core@6.4.1
✓ Package published

Publisher token

In order to publish to the AIR package repository you will need a publisher token. Publisher tokens are placed in your user .apm_config file when you call the following:

apm config set publisher_token XXXXXXXX

Currently these can only be issued directly. Please contact us if you wish to publish a package.

Example

The following process illustrates the basic process to create a package. We will leave most options as the defaults.

  1. Create your package in a directory PACKAGE_NAME (this is just a directory name we are using for organisational purposes):
apm create PACKAGE_NAME
  • Set your package name and identifier, eg com.example.package
  • Set the type to match your package type (swc / src / ane)
  • Set the version, eg 1.0.0
  1. Copy your library to the appropriate directory eg library.swc copy to PACKAGE_NAME/swc/library.swc

  2. Edit README.md to describe your package

  3. Edit package.json setting the url where you plan to upload the file to. We suggest using github releases:

https://github.com/ORGANISATION/REPOSITORY/releases/download/VERSION/com.example.package_1.0.0.airpackage

eg

https://github.com/distriqt/example-package/releases/download/v1.0.0/com.example.package_1.0.0.airpackage
  1. Build your airpackage:
apm build PACKAGE_NAME
  • This will create the package eg: com.example.package_1.0.0.airpackage
  1. Upload to your url, if you are using github releases we suggest the following :

Note: You can use the github client to easily create and upload assets, we use this tool to automate releases and package uploads. It is a super useful tool for anyone using github and highly recommended.

  1. Publish the airpackage to the repository, eg:
apm publish com.example.package_1.0.0.airpackage