AppForShareOpen dashboard

Docs

In-app update check for test builds

Testers keep using the build they installed last week. With a few lines in your app, a test build can ask its channel for the newest build and offer to install it. There is no SDK: each channel has a public JSON address. Find it under Projects, Testing, Update check, next to the channel link. Pro and Team.

The answer

platform is ios or android. build is the build number (iOS CFBundleVersion, Android versionCode) of the newest build put into the channel; putting an older build back is what apps then see. Release notes are left out for password protected builds. The answer can be cached for a minute. A channel without a build for that platform answers 404.

GET https://appforshare.io/api/c/YOUR_CHANNEL/latest?platform=android

{
  "channel": "Beta",
  "platform": "android",
  "version": "2.4.0",
  "build": "118",
  "releaseNotes": "Fixes the login crash",
  "installUrl": "https://appforshare.io/i/AbC123",
  "channelUrl": "https://appforshare.io/c/YOUR_CHANNEL",
  "publishedAt": "2026-11-01T10:00:00.000Z"
}

Swift (iOS)

Compares CFBundleVersion with the channel build number. Call it when the app becomes active.

struct Latest: Decodable { let build: String?; let version: String?; let installUrl: String }

func checkForTestUpdate() async {
    guard let url = URL(string: "https://appforshare.io/api/c/YOUR_CHANNEL/latest?platform=ios"),
          let (data, _) = try? await URLSession.shared.data(from: url),
          let latest = try? JSONDecoder().decode(Latest.self, from: data),
          let mine = Bundle.main.infoDictionary?["CFBundleVersion"] as? String,
          let theirs = latest.build,
          theirs.compare(mine, options: .numeric) == .orderedDescending,
          let install = URL(string: latest.installUrl) else { return }
    await MainActor.run {
        // Show your own alert first, then:
        UIApplication.shared.open(install)
    }
}

Kotlin (Android)

Compares versionCode with the channel build. Run it off the main thread.

suspend fun checkForTestUpdate(context: Context) = withContext(Dispatchers.IO) {
    val json = runCatching { JSONObject(URL("https://appforshare.io/api/c/YOUR_CHANNEL/latest?platform=android").readText()) }.getOrNull() ?: return@withContext
    val theirs = json.optString("build").toLongOrNull() ?: return@withContext
    val info = context.packageManager.getPackageInfo(context.packageName, 0)
    if (theirs > PackageInfoCompat.getLongVersionCode(info)) withContext(Dispatchers.Main) {
        // Show your own dialog first, then:
        context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(json.getString("installUrl"))))
    }
}

Flutter

Uses the http, package_info_plus and url_launcher packages. Build numbers are compared as whole numbers.

Future<void> checkForTestUpdate() async {
  final platform = Platform.isIOS ? 'ios' : 'android';
  final res = await http.get(Uri.parse('https://appforshare.io/api/c/YOUR_CHANNEL/latest?platform=$platform'));
  if (res.statusCode != 200) return;
  final latest = jsonDecode(res.body) as Map<String, dynamic>;
  final mine = int.tryParse((await PackageInfo.fromPlatform()).buildNumber) ?? 0;
  final theirs = int.tryParse('${latest['build']}') ?? 0;
  if (theirs > mine) {
    // Show your own dialog first, then:
    await launchUrl(Uri.parse(latest['installUrl']), mode: LaunchMode.externalApplication);
  }
}

React Native and Expo

Uses expo-application (or DeviceInfo.getBuildNumber() from react-native-device-info).

import { Linking, Platform } from 'react-native';
import * as Application from 'expo-application';

export async function checkForTestUpdate() {
  const res = await fetch(`https://appforshare.io/api/c/YOUR_CHANNEL/latest?platform=${Platform.OS}`);
  if (!res.ok) return;
  const latest = await res.json();
  if (Number(latest.build) > Number(Application.nativeBuildVersion)) {
    // Show your own dialog first, then:
    Linking.openURL(latest.installUrl);
  }
}

Questions

Which plan do I need?
Pro or Team, the plans with channels. The check reads the channel your build was put into.
Should this run in my App Store or Google Play build?
No, and it should not be in them at all. Compile it only into a beta flavor or configuration, not behind a runtime switch. App Store guideline 2.5.2 and Google Play's policy on self updating apps do not allow it in store builds, and Google says such code can count even when it never runs.
Is there an SDK?
No. It is one public JSON address per channel and a few lines in your own code, so nothing is added to your app beyond what you write.
What does a tester see when they tap install?
The same install page as the link and QR code. On iPhone the build must include the device, as with any ad hoc build.

Channels and how to promote builds into them: Beta and Live channels.