Limited Time Offer!
For Less Than the Cost of a Starbucks Coffee, Access All DevOpsSchool Videos on YouTube Unlimitedly.
Master DevOps, SRE, DevSecOps Skills!

0) The symptoms you’ll see
Namespace not specified. Specify a namespace in the module's build file
Error: Couldn't resolve the package 'paytm' in 'package:paytm/paytm.dart'
FileSystemException ... org-dartlang-untranslatable-uri: package%3Apaytm%2Fpaytm.dart
- “SDK processing. This version only understands SDK XML versions up to 3… version 4 was encountered” (a harmless warning once the main issues are resolved)
Root causes, in short:
- AGP 8+ requires
namespace
in every Android module (android { namespace "..." }
). - The deprecated
paytm
plugin is incompatible with AGP 8, and you had code importing it. - Your app should use
paytm_allinonesdk
instead, with the correct method calls and callback URL.
1) What you should use in 2025
- Preferred Paytm plugin for Flutter:
paytm_allinonesdk
- Do not use:
paytm
(older package; causes AGP issues and missing API errors)
Pubspec (good):
dependencies:
flutter:
sdk: flutter
paytm_allinonesdk: ^1.2.6
provider: ^6.1.2
http: ^1.2.1
# ...anything else you need
Remove this if present:
# ❌ remove
paytm: ^3.0.1
Run:
flutter clean
flutter pub get
2) Android Gradle Plugin 8+ requires namespace
Open android/app/build.gradle
and make sure you have:
android {
namespace "com.example.flutter_application_1" // <-- use your real package
compileSdkVersion 34
defaultConfig {
applicationId "com.example.flutter_application_1"
minSdkVersion 21
targetSdkVersion 34
// ...
}
// ...
}
If you saw the namespace error in a plugin module, it’s because that plugin is outdated (like
paytm
). Removing that plugin (and its imports) solves it. If you must keep an old plugin (not recommended), see Section 10 for a temporary Gradle workaround.
3) Replace legacy Paytm calls with All-in-One SDK
3.1 Imports (Dart)
Old (remove):
import 'package:paytm/paytm.dart';
New:
import 'package:paytm_allinonesdk/paytm_allinonesdk.dart';
3.2 ViewModel method (drop-in)
Below is a complete replacement for your makePayment(...)
method that works with paytm_allinonesdk
, handles emulator web flow, and navigates on success/failure.
Future<Map<String, dynamic>> makePayment({
required double totalSum,
required double gst,
required double sumGst,
required List<String> cartId,
required String email,
required List<CartDetail> cartDetail,
required String currency,
required List<int> proid,
required List<String> influencername,
required List<String> influenceremail,
required List<int> influnceradminid,
required BuildContext context,
}) async {
isLoading = true;
notifyListeners();
try {
final String orderId = generateOrderId();
// Get txnToken from YOUR backend (never generate it on device)
final String txnToken = await api.generateTransactionTokens(
orderId: orderId,
totalSum: totalSum,
gst: gst,
sumGst: sumGst,
cartId: cartId,
email: email,
currency: currency,
proid: proid,
influencername: influencername,
influenceremail: influenceremail,
influnceradminid: influnceradminid,
);
const bool isStaging = true; // set to false in production
final String callbackUrl = isStaging
? 'https://securegw-stage.paytm.in/theia/paytmCallback?ORDER_ID=$orderId'
: 'https://securegw.paytm.in/theia/paytmCallback?ORDER_ID=$orderId';
// Emulator often lacks Paytm app; force webview route:
final bool restrictAppInvoke = true;
final result = await AllInOneSdk.startTransaction(
'COTOCU83816930595730', // <-- replace with your MID
orderId,
totalSum.toStringAsFixed(2),
txnToken,
callbackUrl,
isStaging,
restrictAppInvoke,
);
final Map<String, dynamic> res = Map<String, dynamic>.from(result as Map);
final String status = (res['STATUS'] ?? res['resultStatus'] ?? '').toString();
if (status == 'TXN_SUCCESS') {
Navigator.push(
context,
MaterialPageRoute(builder: (_) => OrderSuccessScreen(orderId: orderId)),
);
return {
'status': 'success',
'orderId': orderId,
'gateway': res,
};
} else {
// If you have a Cancelled() screen, navigate there
Navigator.push(
context,
MaterialPageRoute(builder: (_) => const Cancelled()),
);
return {
'status': 'failure',
'orderId': orderId,
'gateway': res,
};
}
} catch (e, st) {
print('Paytm error: $e');
print(st);
return {'status': 'error', 'errorMessage': e.toString()};
} finally {
isLoading = false;
notifyListeners();
}
}
Your UI screen can keep its button that calls
influencerViewModel.makePayment(...)
.
Remove theimport 'package:paytm/paytm.dart';
from any widget files.
4) Backend: generating the Paytm transaction token
Never generate the token on the device. Your server should:
- Create an order in your system (with
orderId
). - Call Paytm’s token/checksum API using your merchant key.
- Return the
txnToken
to the app.
Pseudo-example (Node/Express):
app.post('/paytm/token', async (req, res) => {
const { orderId, amount, customerId } = req.body;
// Build body as per Paytm docs (MID, ORDER_ID, TXN_AMOUNT, CUST_ID, CALLBACK_URL, etc.)
// Sign with merchant key to create checksum/token.
// Send to Paytm, get txnToken, return it to client:
return res.json({ txnToken: "<server-generated-token>" });
});
Your Flutter code calls this endpoint via api.generateTransactionTokens(...)
.
5) Android app setup sanity checklist
- Internet permission in
android/app/src/main/AndroidManifest.xml
:
<uses-permission android:name="android.permission.INTERNET"/>
MainActivity
only needs to be aFlutterFragmentActivity
if you ever see an error like
“Plugin requires a FragmentActivity”:
class MainActivity : FlutterFragmentActivity() // only if needed
- Min/Target SDK: typical
minSdkVersion 21
,targetSdkVersion 34
. - Proguard/R8: usually no special rules needed for All-in-One SDK, but if you obfuscate and hit class-not-found, temporarily disable minify to test.
- Emulator: set
restrictAppInvoke = true
to force webview flow when Paytm app isn’t installed.
6) Common errors & fixes
A) “Namespace not specified…”
- Add
namespace
inandroid/app/build.gradle
(Section 2). - If it’s inside a plugin (like
:paytm
), update/remove the plugin. Usingpaytm_allinonesdk
fixes it.
B) “Couldn’t resolve package ‘paytm’…”
- You still have
import 'package:paytm/paytm.dart';
somewhere. Remove it. - Ensure
pubspec.yaml
does not listpaytm
. Onlypaytm_allinonesdk
.
C) “SDK processing… XML versions up to 3; version 4 encountered”
- Command-line tools vs Android Studio mismatch. It’s a warning. Fix by updating SDK command-line tools later (
sdkmanager --update
). Not a blocker.
D) Callback mis-match / order not found
- Ensure your callback URL matches environment:
- Staging:
https://securegw-stage.paytm.in/theia/paytmCallback?ORDER_ID=$orderId
- Prod :
https://securegw.paytm.in/theia/paytmCallback?ORDER_ID=$orderId
- Staging:
- Make sure
ORDER_ID
is exactly the same on device, token generation, and callback.
E) Activity
/FragmentActivity
errors
- If the plugin demands
FragmentActivity
, changeMainActivity
base class as shown above.
F) “Duplicate class …” after adding libraries
- You likely pulled two overlapping dependencies. Remove the redundant one; avoid keeping both
paytm
andpaytm_allinonesdk
.
G) JAVA_HOME / Gradle version errors
- Use a supported JDK (e.g., 17) for modern AGP.
- If you must temporarily run older AGP to keep a legacy plugin:
classpath 'com.android.tools.build:gradle:7.4.2'
distributionUrl=.../gradle-7.6-all.zip
But the recommended path is not downgrading—fix the plugin instead.
7) End-to-end test steps
- Remove
paytm
frompubspec.yaml
. Keeppaytm_allinonesdk
.flutter clean && flutter pub get
- Add namespace in
android/app/build.gradle
. - Ensure callback URL and MID are correct for staging/prod.
- Ensure server endpoint returns a valid
txnToken
. - On emulator:
restrictAppInvoke: true
. - Run:
flutter run
. - Complete the flow → verify success landing screen and server logs.
8) Production switch checklist
- Set
isStaging = false
- Update
callbackUrl
to production - Ensure your server uses production Paytm keys
- Verify order/accounting handling on success/failure
9) Full minimal snippets to copy
Import:
import 'package:paytm_allinonesdk/paytm_allinonesdk.dart';
Helper (optional):
Future<Map<String, dynamic>> _startPaytmTransactionAIO({
required String mid,
required String orderId,
required String amount,
required String txnToken,
required String callbackUrl,
bool isStaging = false,
bool restrictAppInvoke = false,
}) async {
try {
final result = await AllInOneSdk.startTransaction(
mid, orderId, amount, txnToken, callbackUrl, isStaging, restrictAppInvoke,
);
return Map<String, dynamic>.from(result as Map);
} catch (e) {
return {'STATUS': 'TXN_FAILURE', 'ERROR_MESSAGE': e.toString()};
}
}
Make payment (drop-in): use the big method from Section 3.2.
Android build.gradle
(module: app):
android {
namespace "com.yourcompany.yourapp"
compileSdkVersion 34
defaultConfig {
applicationId "com.yourcompany.yourapp"
minSdkVersion 21
targetSdkVersion 34
}
}
10) (Optional) Temporary workaround for legacy plugins (not recommended)
If you’re forced to keep a very old Android plugin that lacks namespace
, you can inject a fallback in android/build.gradle
(project-level) that sets namespace
from the plugin’s AndroidManifest.xml
:
subprojects { subproject ->
afterEvaluate {
def hasAndroid = subproject.plugins.hasPlugin('com.android.application') || subproject.plugins.hasPlugin('com.android.library')
if (hasAndroid) {
def androidExt = subproject.extensions.findByName("android")
if (androidExt != null && androidExt.hasProperty("namespace") && androidExt.namespace == null) {
def manifest = file("${subproject.projectDir}/src/main/AndroidManifest.xml")
if (manifest.exists()) {
def txt = manifest.getText('UTF-8')
def m = (txt =~ /package="(.*?)"/)
if (m.find()) {
androidExt.namespace = m.group(1)
println "Set namespace for ${subproject.name} -> ${androidExt.namespace}"
}
}
}
}
}
}
But seriously—prefer removing the legacy plugin (like paytm
) and using paytm_allinonesdk
.
11) Quick FAQ
- Do I need the Paytm app installed on device?
No. UserestrictAppInvoke: true
to force webview flow (handy on emulators). - Where do I put merchant key?
On your server only (used to generatetxnToken
). Never ship merchant keys in your app. - Why am I still seeing the old errors?
You likely still have the old importpackage:paytm/paytm.dart
in some file. Global-search your project forpaytm/paytm.dart
and remove it.
12) Final sanity script (run these)
# 1) Ensure only All-in-One SDK is present
grep -R "package:paytm/paytm.dart" -n lib || echo "No legacy paytm import found ✅"
# 2) Clean & get
flutter clean
flutter pub get
# 3) Build & run
flutter run
Leave a Reply