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.15ArnaconWeb3Firebase required
1 Install2 Host3 Init4 Message5 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