Mobile App
One Flutter app for job seekers and employers: set up, brand and publish
About the App
AppSourceCode/ is one Flutter project that builds one app for Android and iOS. It serves both job seekers and employers: after login the app reads the account type and opens the matching experience. Sign-up offers both a job seeker form and a company form.
The app talks to your JobNect website through its API (/api/v10). Everything users see (jobs, settings, logos, onboarding slides, texts and languages) comes from your website, so most changes are made in the admin panel, not in the app code.
Install and configure the website first (Quick Start). The app needs a working site on HTTPS.
Requirements
| Tool | Version |
|---|---|
| Flutter | 3.44 (stable channel) |
| Dart | SDK ^3.12 (comes with Flutter 3.44) |
| Android | Android Studio with the Android SDK, and JDK 17 or newer (the JDK bundled with Android Studio works). The project uses Gradle 8.12, Android Gradle Plugin 8.9.1 and Kotlin 2.1.0; minimum SDK follows the Flutter default. |
| iOS | A Mac with Xcode and CocoaPods. Deployment target iOS 14.0. |
| Accounts | Google Play Console and/or Apple Developer Program to publish |
Check your setup with:
flutter --version
flutter doctor
Open and Run
- Open the
AppSourceCodefolder in Android Studio (or VS Code with the Flutter extension). - Get the packages:
flutter pub get - Start an emulator or connect a phone, then run:
flutter run
Out of the box the app points at the live demo site, so it runs immediately. Before you build your own version, point it at your site (next section).
Connect the App to Your Site
There is one setting to change: lib/shared/config/app_config.dart.
/// The one setting to change before building: your JobNect website address,
/// without a trailing slash. Applicant and employer screens both use it.
class AppConfig {
static const String apiHost = 'https://your-domain.com';
}
- Use your full website address with
https://and no trailing slash. - Both the job seeker and the employer parts of the app read this value (through
lib/applicant/services/urls.dartandlib/employer/services/urls.dart, which add/api/v10). - After changing it, stop the app and run it again (a hot reload does not pick up a changed constant reliably).
Login in the app uses JWT tokens signed with JWT_SECRET from the website’s .env. The web installer creates it. If you change it later, everyone is logged out of the app.
One App, Two Roles
- Logged-out users see onboarding, login and sign-up. Sign-up has a job seeker form and a company form.
- At login the website returns the account type. A job seeker lands in the job seeker home; a company lands in the employer dashboard, with its own theme and bottom navigation.
- The session is remembered: the next launch opens the right experience directly. Logging out returns to the shared login screen.
- Right-to-left languages (for example Hebrew) switch the whole app layout to RTL.
App Name, Package ID and Bundle ID
App name
| Platform | File | Value |
|---|---|---|
| Android | android/app/src/main/AndroidManifest.xml | android:label="JobNect" |
| iOS | ios/Runner/Info.plist | CFBundleDisplayName (and CFBundleName) |
| Flutter | lib/main.dart | title: 'JobNect' |
Android package ID
The app ships with com.bugbuild.jobnect.jobseeker. Use your own before publishing (for example com.yourcompany.jobs); it cannot be changed after the first upload to Google Play.
- In
android/app/build.gradle.ktschange bothnamespaceandapplicationId. - Move
MainActivity.ktfromandroid/app/src/main/kotlin/com/bugbuild/jobnect/jobseeker/to a folder that matches the new ID, and change thepackageline at its top to the same value. - Run
flutter cleanand build again.
iOS bundle ID
Open ios/Runner.xcworkspace in Xcode, select the Runner target, Signing & Capabilities, and set your Bundle Identifier (it ships as com.bugbuild.jobnect.jobseeker) and your Team.
Map tiles
The employer location map uses OpenStreetMap tiles and identifies the app to the tile server. Replace com.jobnect.employer and jobnect-employer-app with your own package name in lib/employer/widgets/location_map_view.dart and lib/employer/widgets/location_map_picker.dart.
Icons, Splash and Colours
Launcher icon
Android icons are in android/app/src/main/res/mipmap-*/ic_launcher.png; iOS icons in ios/Runner/Assets.xcassets/AppIcon.appiconset. Replace them by hand, or generate all sizes from one 1024 × 1024 PNG with the flutter_launcher_icons package:
# pubspec.yaml
dev_dependencies:
flutter_launcher_icons: ^0.14.0
flutter_launcher_icons:
android: true
ios: true
image_path: "assets/images/app-icon.png"
remove_alpha_ios: true
flutter pub get
dart run flutter_launcher_icons
Splash screen
- The short native launch screen is
android/app/src/main/res/drawable-v21/launch_background.xmlon Android andios/Runner/Base.lproj/LaunchScreen.storyboardon iOS. - The app’s own splash then shows the App logo, on colour from your website (admin , Branding). Change the logo there; no rebuild is needed.
- The onboarding slides come from in the admin panel.
Colours and fonts
The main colour is colorPrimary in lib/applicant/utils/app_colors.dart and lib/employer/utils/app_colors.dart. The font (Kumbh Sans) is in assets/fonts/ and declared in pubspec.yaml.
Payment Return Link (jobnect://)
Online payments open the gateway’s hosted checkout in the browser. When the payment is finished, the website sends the user back to the app through a link that starts with jobnect://, and the app shows the result. The scheme is registered in:
| Where | What |
|---|---|
android/app/src/main/AndroidManifest.xml | An intent-filter with <data android:scheme="jobnect"/> |
ios/Runner/Info.plist | CFBundleURLTypes → CFBundleURLSchemes = jobnect |
lib/employer/controllers/payment_redirect_controller.dart | Handles incoming jobnect:// links |
lib/employer/screens/secure_checkout_screen.dart | Return and cancel links sent with a payment |
Keep jobnect:// unless you have a reason to change it. The website also checks this scheme before it redirects (in app/Http/Controllers/Api/V10/PricingPlansController.php and app/Http/Controllers/Backend/StripeController.php), so a new scheme has to be changed in the app files above and in those two website files.
Android Signing
No keystore is included: you create your own. Keep the keystore and its passwords safe; you need the same key for every update on Google Play.
- Create a keystore (from the
AppSourceCodefolder):keytool -genkey -v -keystore android/app/upload-keystore.jks -keyalg RSA -keysize 2048 -validity 10000 -alias upload - Create
android/key.properties:storePassword=your-store-password keyPassword=your-key-password keyAlias=upload storeFile=upload-keystore.jksstoreFileis relative toandroid/app/; an absolute path also works.
android/app/build.gradle.kts already reads key.properties. When the file is missing, release builds fall back to the debug key: fine for testing, but Google Play rejects them.
Do not commit key.properties or the .jks file to a public repository.
Build for Android
Set the version in pubspec.yaml first. It ships as version: 2.0.0+3 (name + build number); raise the build number for every upload.
flutter clean
flutter pub get
flutter build apk --release # build/app/outputs/flutter-apk/app-release.apk
flutter build appbundle --release # build/app/outputs/bundle/release/app-release.aab
Upload the .aab to Google Play Console. Use the .apk to install directly on phones for testing.
Build for iOS
- Install the pods:
flutter pub get cd ios pod install cd .. - Open
ios/Runner.xcworkspace(not the.xcodeproj) in Xcode. In Runner → Signing & Capabilities choose your team and bundle identifier. - Build the archive, either in Xcode with Product → Archive and then Distribute App, or from the terminal:
and uploadflutter build ipa --releasebuild/ios/ipa/*.ipawith Transporter or Xcode.
The app asks for camera and photo library access (profile photos, documents). The texts shown to the user are NSCameraUsageDescription and NSPhotoLibraryUsageDescription in ios/Runner/Info.plist; adjust them to describe your use before submitting to the App Store.
Link the Website to Your Store Pages
Once the app is live, open in the admin panel and paste your Google Play and App Store addresses. Download buttons then appear in every footer style and in the newsletter sections. Each store has its own on/off switch, plus one switch for all buttons.
App Themes
The app has three looks. You choose one in the admin panel under ; there is nothing to change in the app code.
| Theme | Style |
|---|---|
| Classic | The original teal look: soft cards, rounded buttons, a calm white background. |
| Momentum | Most trending: warm paper background, bold headings, a dark hero card with lime highlights, pill buttons and a floating pill navigation bar. |
| Meridian | Professional: navy and cobalt, crisp 12 px corners, clean bordered cards and a flat navigation bar. |
- Follow the website theme (the default) gives Momentum and Meridian sites the matching app look; the other website themes use Classic.
- Every screen follows the chosen colours, fonts, corners, buttons and inputs. Onboarding, sign-in, both home screens, job cards, job details and profile also get their own layout per theme.
- The app reads the theme from
GET /api/v10/settings(app_theme) each time it opens. It starts with the last theme it saw, so there is no flash, and switches as soon as a new one arrives.
To change a theme's colours, edit its palette in lib/shared/theme/app_skin.dart (AppSkin.classic, AppSkin.momentum, AppSkin.meridian).
Troubleshooting
| Problem | Fix |
|---|---|
| App shows no data or "connection" errors | Check AppConfig.apiHost: full https address, no trailing slash. Open https://your-domain.com in the phone browser to confirm the site works there. |
| Login fails on the app but works on the website | JWT_SECRET must be set in the website .env; run php artisan optimize:clear after setting it. |
| Images do not load in the app | Set APP_URL in the website .env to the https address and make public/uploads/ readable. |
| After payment the app does not reopen | Keep the jobnect scheme in AndroidManifest.xml and Info.plist (see Payment Return Link). Reinstall the app after changing either file. |
| Gradle or Kotlin version errors | Use Flutter 3.44 and JDK 17+, then run flutter clean and flutter pub get. |
| iOS: "Module not found" or pod errors | Run cd ios && pod install --repo-update and open Runner.xcworkspace. |
| Release APK rejected by Google Play | It was signed with the debug key: create android/key.properties and the keystore (Android Signing). |
| Old texts or logo after changing them on the website | The app caches settings and texts. Clear the app’s storage or reinstall it. |