Android · Java

Android quickstart

Vendor the JAR. Use the open-source wrapper. Init, then send a message and a call notification. There is no Maven artifact.

JAR 0.4.15 ArnaconWeb3 Firebase required
1 Install 2 Host 3 Init 4 Message 5 Call

1. Install

Ship Arnacon-0.4.15.jar with the app. The open-source client already does this via a file tree. Do not invent a Maven coordinate.

Gradleapp/build.gradle
implementation(fileTree(dir: 'libs', include: ['*.jar', '*.aar']))

// Place in app/libs/:
//   Arnacon-0.4.15.jar
// Source of truth:
//   github.com/cellact/Arnacon_Android_Client_OpenSource
// Wrapper:
//   com.arnacon.app.arnacon.ArnaconWeb3
// JAR type behind it:
//   org.Arnacon

If the GitHub repo returns 404, you do not have access yet. Copy the JAR and the wrapper from a checkout you are allowed to use. Do not pin a version that is not in app/libs/.

2. Host pieces

The JAR needs the same three roles as iOS: persistence, server, logger. The open-source app already has them. Copy these, do not invent a new persistence format.

  • PreferencesDataSaver extends org.ArnaconPackages.Storage.ADataSaver and writes string keys to SharedPreferences.
  • AppKeyManager.getAppKey(context) is Android’s encryption password. It is a Keystore-wrapped random key, not GPS and not a phone number.
  • CloudFunctions.getCloudFunctions(logger) is the shipped IServer.
  • Firebase Cloud Messaging must be on the app. The wrapper registers the token after network settings succeed.
PreferencesDataSaverADataSaver
public class PreferencesDataSaver extends ADataSaver {
    private final Context context;

    public PreferencesDataSaver(Context context) {
        this.context = context;
    }

    public void setPreference(String key, String value) {
        PreferencesHelper.setPreference(context, key, value);
    }

    public String getPreference(String key, String defaultValue) {
        return PreferencesHelper.getPreference(context, key, defaultValue);
    }

    @Override
    public void resetPreferences() {
        context.getSharedPreferences("AppData", Context.MODE_PRIVATE)
            .edit().clear().apply();
    }
}

3. Init

The wrapper constructs org.Arnacon with the data saver and the app key, then connects the server when the network is up.

AndroidArnaconWeb3
ArnaconWeb3 sdk = ArnaconWeb3.getInstance(context);
sdk.setNetworkSettings();

// Inside the wrapper (do not skip this):
// appKey = AppKeyManager.getAppKey(context);
// web3Service = new Arnacon(new PreferencesDataSaver(context), appKey);
// server = CloudFunctions.getCloudFunctions(logger);
// web3Service.setNetworkSettings(server);

Wait for isNetworkSettingsReady() or NetworkSettingsReadyListener before identity or send calls. The wrapper queues setNetworkSettings on first network availability so a cold start does not race.

4. Identity

Main coordinates come from the install, not from a phone number. Installed identities are products. Labels are what the user sees.

Androididentity
String me = sdk.getPublicKey(); // main coordinates
String owner = sdk.getENSOwner("alice.arnacon.global", false);
String xdata = sdk.getXData();
String xsign = sdk.getXSign(xdata);
String signed = sdk.signMessage(message);
boolean mine = sdk.checkIdentity("alice");

installProduct(item) adds an identity. Live Android still auto-installs some ITEM payloads. The intended policy — implement this — is that the user Allows. Never auto-run it in new code.

5. First message

The wrapper’s sendFCMMessage is prepare + execute with NotificationType.MESSAGE. Pass the local identity, the remote identity, and the payload.

AndroidMESSAGE
sdk.sendFCMMessage(
    "alice.arnacon.global",
    "bob.arnacon.global",
    "Hello from Alice"
);

// Same path, explicit plan (JAR):
PreparedNotification prepared = web3Service.prepareNotification(
    "alice.arnacon.global",
    "bob.arnacon.global",
    "Hello from Alice",
    DefaultParameters.NotificationType.MESSAGE,
    true
);
NotificationResult result = web3Service.executeNotification(prepared);

For a chat body without a WebRTC session, the wrapper also exposes sendPlaintextMessage. After WebRTC fails, sendFallbackMessage uses NotificationType.FALLBACK so the remote chat pipeline stores the text.

6. First call

Ring with sendCallNotification. That is prepare + execute with NotificationType.CALL. Your WebRTC (or SIP) stack still owns media.

AndroidCALL
sdk.sendCallNotification(
    "alice.arnacon.global",
    "bob.arnacon.global",
    "Incoming call"
);

// SDP / ICE / cancel / reject / end — do not ring again:
sdk.sendRealtimeSignal(localId, remoteId, signalJson);

The store app’s WebRTC layer also sends some signaling as FCM JSON. Use REALTIME_SIGNAL for ephemeral protocol messages so the recipient does not present an incoming-call UI.

7. Push tokens

Register this device. Firebase is required. Do not push tokens for someone else.

Androidthis device
sdk.sendFcmToken(fcmToken);

The wrapper calls this after setNetworkSettings if a token has not been sent yet. Your FirebaseMessagingService should call it again when the token rotates.

What the host still owns

  • WebRTC or SIP media, the in-call UI, and audio routing
  • Chat storage and the message list
  • google-services.json and notification channels
  • The Allow dialog before installProduct
  • Payments and store checkout
Never expose from the host app:
  • The Keystore app key, mnemonic, or private keys
  • Sending as an identity the user did not select
  • A Maven coordinate that does not exist

Next

Concepts, then the other platform.