I'm trying to send notifications from an Node.js API to a Flutter application.
First, I want to make my application able to receive notifications from Firebase.
But, when I initializeApp, I got an issue :
PlatformException (PlatformException(null-error, Host platform
returned null value for non-null return value., null, null))
and this, in the console:
E/flutter (25357): [ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: PlatformException(null-error, Host platform returned null value for non-null return value., null, null)
E/flutter (25357): #0 FirebaseCoreHostApi.optionsFromResource (package:firebase_core_platform_interface/src/pigeon/messages.pigeon.dart:250)
package:firebase_core_platform_interface/…/pigeon/messages.pigeon.dart:1
E/flutter (25357): <asynchronous suspension>
E/flutter (25357): #1 MethodChannelFirebase.initializeApp (package:firebase_core_platform_interface/src/method_channel/method_channel_firebase.dart:89)
package:firebase_core_platform_interface/…/method_channel/method_channel_firebase.dart:1
E/flutter (25357): <asynchronous suspension>
E/flutter (25357): #2 Firebase.initializeApp (package:firebase_core/src/firebase.dart:40)
package:firebase_core/src/firebase.dart:1
E/flutter (25357): <asynchronous suspension>
E/flutter (25357): #3 main (package:notifappfcm/main.dart:13)
package:notifappfcm/main.dart:1
I've been looking for a solution to this problem, but I really can't find it.
This is my application code:
main.dart
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'mainscreen.dart';
Future<void> _firebadeMessagingBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp(); // options: DefaultFirebaseConfig.platformOptions
print('Handling a background message ${message.messageId}');
}
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
FirebaseMessaging.onBackgroundMessage(_firebadeMessagingBackgroundHandler);
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MainScreen(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
mainscreen.dart
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
class MainScreen extends StatefulWidget {
const MainScreen({Key? key}) : super(key: key);
#override
State<MainScreen> createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
late AndroidNotificationChannel channel;
late FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
#override
void initState() {
super.initState();
requestPermission();
loadFCM();
listenFCM();
// Get device's notification token
getToken();
}
void getToken() async {
await FirebaseMessaging.instance.getToken().then((token) => print(token));
}
void requestPermission() async {
FirebaseMessaging messaging = FirebaseMessaging.instance;
NotificationSettings settings = await messaging.requestPermission(
alert: true,
announcement: false,
badge: true,
carPlay: false,
criticalAlert: false,
provisional: false,
sound: true,
);
if (settings.authorizationStatus == AuthorizationStatus.authorized) {
print('User granted permission');
} else if (settings.authorizationStatus ==
AuthorizationStatus.provisional) {
print('User granted provisional permission');
} else {
print('User declined or has not accepted permission');
}
}
void listenFCM() async {
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
RemoteNotification? notification = message.notification;
AndroidNotification? android = message.notification?.android;
if (notification != null && android != null && !kIsWeb) {
flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: AndroidNotificationDetails(channel.id, channel.name,
// ignore: todo
// TODO add a proper drawable resource to android (now using one that already exists)
icon: 'launch_background')));
}
});
}
void loadFCM() async {
if (!kIsWeb) {
channel = const AndroidNotificationChannel(
'high_importance_channel', // id
'High Importance Notifications', // title
importance: Importance.high,
enableVibration: true,
);
flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
/// Create an Android Notification Channel.
///
/// We use this channel in the `AndroidManifest.xml` file to override the
/// default FCM channel to enable heads up notifications.
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
/// Update the iOS foreground notification presentation options to allow
/// heads up notifications.
await FirebaseMessaging.instance
.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
height: 40,
width: 200,
color: Colors.red,
),
));
}
}
Make sure you have added the Firebase SDK dependencies in the
Project Level build.gradle file
and Application Level build.gradle file
Dependencies to be added in Project Level build.gradle:
buildscript {
repositories {
// Check that you have the following line (if not, add it):
google() // Google's Maven repository
}
dependencies {
...
// Add this line
classpath 'com.google.gms:google-services:4.3.13'
}
}
allprojects {
...
repositories {
// Check that you have the following line (if not, add it):
google() // Google's Maven repository
...
}
}
Dependencies to be added in App Level build.gradle:
apply plugin: 'com.android.application'
// Add this line
apply plugin: 'com.google.gms.google-services'
dependencies {
// Import the Firebase BoM
implementation platform('com.google.firebase:firebase-bom:30.2.0')
// Add the dependency for the Firebase SDK for Google Analytics
// When using the BoM, don't specify versions in Firebase dependencies
implementation 'com.google.firebase:firebase-analytics'
// Add the dependencies for any other desired Firebase products
// https://firebase.google.com/docs/android/setup#available-libraries
}
Make sure you have these settings in your android/build.gradle
buildscript {
repositories {
// Check that you have the following line (if not, add it):
google() // Google's Maven repository
}
dependencies {
// ...
// Add the following line:
classpath 'com.google.gms:google-services:4.3.13' // Google Services plugin
}
}
allprojects {
// ...
repositories {
// Check that you have the following line (if not, add it):
google() // Google's Maven repository
// ...
}
}
And then in your android/app/build.gradle:
apply plugin: 'com.android.application'
// Add the following line:
apply plugin: 'com.google.gms.google-services' // Google Services plugin
android {
// ...
}
You can follow the steps here
And don't forget to download google-service.json from firebase project console, and put it into android/app folder.
Sometimes FlutterFire cli is not able to update build.gradle files so you get the above error
in project level build.gradle add the firebase dependencies as
dependencies {
classpath 'com.android.tools.build:gradle:7.1.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.google.gms:google-services:4.3.10'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.1'
}
in app level build.gradle file apply firebase plugins as
apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.google.firebase.crashlytics'
The accepted answer still definitely works, but it requires manual operations plus the uncertainty of which Google Services version and Firebase BOM to add.
I recommend using the FlutterFire CLI to configure the project and to automatically set up all these build.gradle dependencies.
Official configuration setup can be found here.
Attention. Manually changing build.gradle files as described above is not a solution. It will either won't work or every build will generate lots of warnings as using deprecated dependencies. Correct solution is this:
Firabase should be intialiezed like below:
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
For this, you will need to run some commands from command line / terminal:
// Add firebase core into your project
flutter pub add firebase_core
// Generate firebase options file
flutterfire configure
// Import firebase core and generated file
import 'package:firebase_core/firebase_core.dart';
import 'firebase_options.dart';
For details you can refer here.
This Solution is effective :)
in project level build.gradle add the firebase dependencies as
dependencies {
classpath 'com.android.tools.build:gradle:7.1.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.google.gms:google-services:4.3.10'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.1'
}
in app level build.gradle file apply firebase plugins as
apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.google.firebase.crashlytics'
If you are configuring flutter in ios make sure to initilize this in swift file
FirebaseApp.configure()
import FirebaseCore //import this on top
It looks like you need to set the DefaultFirebaseOptions in await Firebase.initializeApp(); line.
According to this docs, you need to put the options.
Follow this step by step
Run flutter pub add firebase_core
Run flutterfire configure. Skip this if you already configure your project.
In your main.dart, update this in your code.
From
await Firebase.initializeApp();
To
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
Try running your application
I hope this helps to solve this issue.
Thank you for reading!
From:
await Firebase.initializeApp();
To:
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
Works for me!
I'm trying to implement parallel execution of autotests using JUnit 5 and GEB. At the moment, the tests are already running in parallel. The problem is that every page element must be visible at the time the page object is created. If the object was not displayed on the page, then when you try to access it, a new browser object is created with a new page, starting an extra thread. How can this be avoided?
package tests
import geb.Browserimport geb.Pageimport geb.junit5.GebReportingTest
import org.junit.jupiter.api.AfterEachimport org.junit.jupiter.api.BeforeEachimport org.junit.jupiter.api.Testimport org.junit.jupiter.api.extension.ExtendWithimport io.github.bonigarcia.seljup.SeleniumJupiterimport org.openqa.selenium.chrome.ChromeDriver;import pages.CbsLoginPageimport static org.assertj.core.api.Assertions.*
#ExtendWith(SeleniumJupiter.class)class LoginToCbsTest extends GebReportingTest {public Browser browserpublic CbsLoginPage page
#BeforeEach
public void classLevelSetup() {
browser = new Browser()
browser.setDriver(new ChromeDriver())
page = browser.createPage(CbsLoginPage.class)
}
#AfterEach
public void teardown() {
browser.quit()
}
#Test
void loginFailsWhenPasswordIsWrong() {
// When
page.fillCredentialsForm("username", "123_Wrong_password")
page.clickLoginButton()
// Then
verifyLoginErrorIsDisplayed()
}
#Test
void loginFailsWhenUsernameIsWrong() {
// When
page.fillCredentialsForm("Wrong_username", "password")
page.clickLoginButton()
// Then
verifyLoginErrorIsDisplayed()
}
package pages
import geb.Pageimport modules.CbsLoginPageModule
import static geb.Browser.drive
class CbsLoginPage extends Page {static at = { title == "Log in to Application" }
static content = {
loginForm { module(CbsLoginPageModule) }
}
void fillCredentialsForm(String username, String password) {
drive(getBrowser(), {
getBrowser().to(this)
loginForm.loginField.value(username)
loginForm.passwordField.value(password)
})
}
void clickLoginButton() {
drive(getBrowser(), {
getBrowser().at(this)
loginForm.loginButton.click()
})
}
void getErrorMessage() {
drive(getBrowser(), {
getBrowser().at(this)
page
waitFor { $("div", innerHTML: contains("Invalid username or password.")) //This element is not visible when page was created}
})
}
}
package modules
import geb.Module
class CbsLoginPageModule extends Module {
static content = {form { $("form") }
loginField { form.$(id: "name") }
passwordField { form.$(id: "password") }
loginButton { form.$(name: "login") }
}
}
/*This is the Geb configuration file.
See: http://www.gebish.org/manual/current/#configuration
*/
import org.openqa.selenium.chrome.ChromeDriver
waiting {timeout = 2}
environments {
driver = { new ChromeDriver() }
}reportsDir = new File("target/runtime_reports_dir")baseUrl = "url"
plugins {id "idea"id "groovy"}
repositories {mavenCentral()}
dependencies {testImplementation 'io.github.bonigarcia:selenium-jupiter:4.0.1'testImplementation 'org.seleniumhq.selenium:selenium-java:4.1.2'testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.8.1'testImplementation 'org.gebish:geb-junit5:5.1'testImplementation 'org.assertj:assertj-core:3.22.0'}
task chromedriverTest(type: Test) {useJUnitPlatform()}
task chromeheadlessTest(type: Test) {useJUnitPlatform()}
test {useJUnitPlatform()testLogging {events "passed", "skipped", "failed"}
systemProperty("junit.jupiter.execution.parallel.enabled" , "true")
systemProperty("junit.jupiter.execution.parallel.config.strategy", "fixed")
systemProperty("junit.jupiter.execution.parallel.mode.default", "concurrent")
systemProperty("junit.jupiter.execution.parallel.config.fixed.parallelism", 2)
}
Before I have submitted the issue
[ ] I have read an installation guide
[ ] I know that for an iOS I need to install pods because I've read the installation guide
[ ] I have read a linking guide and checked that everything is OK like in manual linking guide
[ ] I know that before using tipsi-stripe I need to set options for my app as described in usage guide
The problem
Error on Android when try to call function deviceSupportNativePay, the error shown as image below
https://user-images.githubusercontent.com/54148306/79314833-6cde0680-7f2c-11ea-888d-e1836c038f98.png
Because I'm using RN 0.61.5, first I'm not using manual link, and on iOS is working just fine, not for android though. Now I try manual link for android, but still same issue. Has been followed many issues on stackoverflow and github with no luck. Can confirm stripe object is not null because already initiated it with setOptions.
Environment
tipsi-stripe version: 7.2.0
Last tipsi-stripe version where the issue was not reproduced (if applicable):
iOS or Android: Android
OS version: any version
React-Native version: 0.61.5
(Android only) com.google.firebase:firebase-core version: 16.0.9
(Android only) com.google.android.gms:play-services-base version: 16.1.0
Related config
/app/build.gradle
apply plugin: "com.android.application"
apply plugin: "io.fabric"
import com.android.build.OutputFile
project.ext.react = [
entryFile: "index.js",
enableHermes: false, // clean and rebuild if changing,
bundleAssetName: "index.android.bundle",
bundleInAlpha: true,
bundleInBeta: true
]
apply from: "../../node_modules/react-native/react.gradle"
apply from: "../../node_modules/react-native-code-push/android/codepush.gradle"
def enableHermes = project.ext.react.get("enableHermes", false);
android {
compileSdkVersion rootProject.ext.compileSdkVersion
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
defaultConfig {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
ndk {
abiFilters "armeabi-v7a", "x86"
}
missingDimensionStrategy 'react-native-camera', 'general'
multiDexEnabled true
renderscriptTargetApi 23
renderscriptSupportModeEnabled true
}
splits {
abi {
reset()
enable enableSeparateBuildPerCPUArchitecture
universalApk false // If true, also generate a universal APK
include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
}
}
signingConfigs {
release {
if (project.hasProperty('MYAPP_RELEASE_STORE_FILE')) {
storeFile file(MYAPP_RELEASE_STORE_FILE)
storePassword MYAPP_RELEASE_STORE_PASSWORD
keyAlias MYAPP_RELEASE_KEY_ALIAS
keyPassword MYAPP_RELEASE_KEY_PASSWORD
}
}
}
buildTypes {
// debug {
// signingConfig signingConfigs.debug
// }
release {
// Caution! In production, you need to generate your own keystore file.
// see https://facebook.github.io/react-native/docs/signed-apk-android.
signingConfig signingConfigs.release
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
}
}
// applicationVariants are e.g. debug, release
applicationVariants.all { variant ->
variant.outputs.each { output ->
// For each separate APK per architecture, set a unique version code as described here:
// https://developer.android.com/studio/build/configure-apk-splits.html
def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
def abi = output.getFilter(OutputFile.ABI)
if (abi != null) { // null for the universal-debug, universal-release variants
output.versionCodeOverride =
versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
}
}
}
dexOptions {
jumboMode true
preDexLibraries = false
// javaMaxHeapSize "4g"
}
configurations.all {
resolutionStrategy {
force 'com.android.support:design:28.0.0'
force 'com.android.support:support-v4:28.0.0'
// force 'com.google.android.gms:play-services-base:16.1.0'
// force 'com.android.support:appcompat-v7:28.0.0'
}
}
}
dependencies {
implementation (project(':tipsi-stripe')){
exclude group: 'com.google.android.gms'
exclude group: 'com.google.firebase'
}
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "com.android.support:support-v4:27.1.0"
implementation "com.android.support:design:27.1.0"
implementation "com.android.support:appcompat-v7:27.1.0"
implementation "com.facebook.react:react-native:+" // From node_modules
// fbsdk
implementation 'com.facebook.android:facebook-android-sdk:[5,6)'
implementation project(':react-native-firebase')
// firebase
implementation "com.google.android.gms:play-services-base:16.1.0"
implementation "com.google.firebase:firebase-core:16.0.9"
// firebase messaging
implementation "com.google.firebase:firebase-messaging:18.0.0"
implementation 'me.leolin:ShortcutBadger:1.1.21#aar' // <-- Add this line if you wish to use badge on Android
// firebase crashlytic
implementation('com.crashlytics.sdk.android:crashlytics:2.9.9#aar') {
transitive = true
}
if (enableHermes) {
def hermesPath = "../../node_modules/hermes-engine/android/";
debugImplementation files(hermesPath + "hermes-debug.aar")
releaseImplementation files(hermesPath + "hermes-release.aar")
} else {
implementation jscFlavor
}
}
// Run this once to be able to run the application with BUCK
// puts all compile dependencies into folder libs for BUCK to use
task copyDownloadableDepsToLibs(type: Copy) {
from configurations.compile
into 'libs'
}
apply from: file("../../node_modules/#react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
apply plugin: 'com.google.gms.google-services'
android/build.gradle
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext {
buildToolsVersion = "28.0.3"
minSdkVersion = 22
compileSdkVersion = 28
targetSdkVersion = 28
googlePlayServicesAuthVersion = "16.0.1"
}
repositories {
mavenCentral()
google()
jcenter()
maven {
url 'https://maven.fabric.io/public'
}
}
dependencies {
classpath("com.android.tools.build:gradle:3.5.3")
classpath("com.google.gms:google-services:4.3.3")
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
classpath 'io.fabric.tools:gradle:1.28.1'
}
}
allprojects {
repositories {
mavenLocal()
google()
jcenter()
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url("$rootDir/../node_modules/react-native/android")
}
maven {
// Android JSC is installed from npm
url("$rootDir/../node_modules/jsc-android/dist")
}
maven { url "https://www.jitpack.io" }
maven { url "https://maven.google.com" }
}
}
ext {
compileSdkVersion = 28
targetSdkVersion = 28
buildToolsVersion = "28.0.3"
supportLibVersion = "28.0.0"
googlePlayServicesVersion = "11.8.0"
androidMapsUtilsVersion = "0.5+"
}
MainApplication.java
import android.app.Application;
import android.content.Context;
import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.soloader.SoLoader;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
// codepush
import com.microsoft.codepush.react.CodePush;
// firebase
import io.invertase.firebase.RNFirebasePackage;
import io.invertase.firebase.messaging.RNFirebaseMessagingPackage;
import io.invertase.firebase.analytics.RNFirebaseAnalyticsPackage;
import io.invertase.firebase.fabric.crashlytics.RNFirebaseCrashlyticsPackage;
import io.invertase.firebase.notifications.RNFirebaseNotificationsPackage;
// google sign-in
import co.apptailor.googlesignin.RNGoogleSigninPackage;
import com.gettipsi.stripe.StripeReactPackage;
import java.util.Arrays;
import java.util.List;
import android.content.Intent;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost =
new ReactNativeHost(this) {
#Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
#Override
protected String getJSBundleFile() {
return CodePush.getJSBundleFile();
}
#Override
protected List<ReactPackage> getPackages() {
#SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// firebase
// packages.add(new RNFirebasePackage());
packages.add(new RNFirebaseMessagingPackage());
packages.add(new RNFirebaseAnalyticsPackage());
packages.add(new RNFirebaseNotificationsPackage());
packages.add(new StripeReactPackage());
return packages;
}
#Override
protected String getJSMainModuleName() {
return "index";
}
};
#Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
#Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, /* native exopackage */ false);
// initializeFlipper(this); // Remove this line if you don't want Flipper enabled
}
/**
* Loads Flipper in React Native templates.
*
* #param context
*/
private static void initializeFlipper(Context context) {
if (BuildConfig.DEBUG) {
try {
/*
We use reflection here to pick up the class that initializes Flipper,
since Flipper library is not available in release mode
*/
Class<?> aClass = Class.forName("com.facebook.flipper.ReactNativeFlipper");
aClass.getMethod("initializeFlipper", Context.class).invoke(null, context);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
react-native.config.js
module.exports = {
dependencies: {
'tipsi-stripe': {
platforms: {
android: null,
},
},
},
};
settings.gradle
include ':tipsi-stripe'
project(':tipsi-stripe').projectDir = new File(rootProject.projectDir, '../node_modules/tipsi-stripe/android')
I'm struggling to get Robotium to work on the gradle-based Android Studio and I can't find the way to run the test with gradle CLI.
I Placed robotium.jar "robotium-solo-5.4.1.jar" into the libs folder, Added as library.
In the src folder I created another folders androidTest->java->package for the test source with the same name as app’s package name-> Test.java
"java" (inside "androidTest") is a green color.
UI: as usual using Android Studio Run menu - working.
console: in the terminal enter the following command: gradlew connectedAndroidTest = not working.
I also tried "gradlew test", test results get generated in build/test-report, but they show that no tests were found.
I want to run Robotium test with gradle CLI without connecting device, because I want to run tests in the Android emulator in CircleCI.
Is there a problem on my build.gradle / test file or is there a something I missing ?
I would really appreciate any help!
***** This is my build.gradle file
apply plugin: 'com.android.application'
apply plugin: 'io.fabric'
android {
compileSdkVersion 22
buildToolsVersion "22.0.1"
dexOptions {
// jumboMode true
javaMaxHeapSize "2g"
}
defaultConfig {
applicationId 'net.example'
minSdkVersion 14
targetSdkVersion 22
versionName '2.8.1'
versionCode 2801
multiDexEnabled true
}
buildTypes {
debug{
debuggable true
jniDebuggable true
}
release {
debuggable false
jniDebuggable false
minifyEnabled true
proguardFiles 'proguard-coda.txt', 'proguard-rules.pro'
}
}
productFlavors {
}
packagingOptions {
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/LICENSE'
exclude 'META-INF/NOTICE'
}
lintOptions {
disable 'MissingTranslation'
}
sourceSets {
androidTest {
java.srcDirs = ['src/androidTest/java']
}
}
}
dependencies {
// Included library modules
...
// My regular dependencies
...
compile fileTree(include: ['*.jar'], dir: 'libs')
// Test dependencies
androidTestCompile 'com.jayway.android.robotium:robotium-solo:5.4.1'
androidTestCompile fileTree(dir: 'libs', include: 'robotium-solo-5.4.1.jar')
}
***** Robotium test file in the Location : app->src->androidTest->java->package name->Test.java
package net.example;
import com.robotium.solo.*;
import android.test.ActivityInstrumentationTestCase2;
import android.view.View;
import java.util.ArrayList;
#SuppressWarnings("rawtypes")
public class Test extends ActivityInstrumentationTestCase2 {
private Solo solo;
//Debug Logcat Tag for filtering
private static final String TAG = "RoboDebug";
private static final String LAUNCHER_ACTIVITY_FULL_CLASSNAME ="net.example.exampleActivity";
private static Class<?> launcherActivityClass;
static{
try {
launcherActivityClass = Class.forName(LAUNCHER_ACTIVITY_FULL_CLASSNAME);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
#SuppressWarnings("unchecked")
public Test() throws ClassNotFoundException {
super(launcherActivityClass);
}
public void setUp() throws Exception {
super.setUp();
solo = new Solo(getInstrumentation());
getActivity();
}
#Override
public void tearDown() throws Exception {
solo.finishOpenedActivities();
super.tearDown();
}
public void testRun() {
//Wait for activity: 'net.example.exampleActivity'
solo.waitForActivity("exampleActivity", 5000);
//Wait for activity: 'coda.RootActivity'
//!!!!!!!!
assertTrue("RootActivity is not found!", solo.waitForActivity("RootActivity"));
//Set default small timeout to 60000 milliseconds
//Click on Beauty
solo.clickOnText(java.util.regex.Pattern.quote("Beauty"));
ArrayList<View> dig = solo.getViews();
android.util.Log.d(TAG, "Dig is: " + dig);
}
}
Im trying to add Joda-Time as a dependency to my UIAutomator test project in Android Studio using Gradle and I get the following error when I try to use the LocalDate class in Joda:
java.lang.NoClassDefFoundError: org.joda.time.LocalDate
Im not sure what Im doing wrong. Im pretty sure my build.gradle and Test Class is correct. This probably isnt a Joda problem...Im just implementing the library wrong.
Here is my gradle.properties:
androidSdkHome=/Users/timbo/sdk
androidSdkTarget=android-20
androidSdkBuildToolsDir=build-tools/android-4.4W/
Heres my build.gradle file:
apply plugin: 'java'
apply plugin: 'idea'
sourceCompatibility = 1.7
targetCompatibility = 1.7
version = '0.1'
project.ext {
dexDir = new File('build/dex')
distDir = new File('./dist')
}
repositories {
mavenCentral()
}
dependencies {
compile fileTree(dir: androidSdkHome + '/platforms/' + androidSdkTarget, include: '*.jar')
compile group: 'junit', name: 'junit', version: '4.11'
compile group: 'joda-time', name: 'joda-time', version: '2.5'
}
jar {
doLast {
tasks.dex.execute()
}
}
task dex(dependsOn: jar, type:Exec) {
println 'Building dex...'
project.dexDir.mkdirs()
workingDir '.'
commandLine androidSdkHome + '/' + androidSdkBuildToolsDir + '/' + 'dx', '--dex', '--no-strict', '--output=' + buildDir +'/dex/' + project.name + '.jar', jar.archivePath
doLast {
tasks.dist.execute()
}
}
task dist(dependsOn:dex, type:Copy) {
project.distDir.mkdirs()
from(project.dexDir)
into(project.distDir)
include('*.jar')
}
Here is my Test:
package com.mofo.hilton.android.uiautomator.tests;
import com.android.uiautomator.core.UiObjectNotFoundException;
import com.android.uiautomator.testrunner.UiAutomatorTestCase;
import org.joda.time.LocalDate;
/**
* Created by TimBo on 10/11/14.
*/
public class TestJodaTime extends UiAutomatorTestCase {
#Override
public void setUp() throws UiObjectNotFoundException {
}
public void testJodaTime() throws UiObjectNotFoundException {
LocalDate dt = new LocalDate();
LocalDate lastDayOfMonth = dt.dayOfMonth().withMaximumValue();
System.out.println(lastDayOfMonth);
}
}
And here is an image of the External libraries that are in my project: