I am getting a failure when trying to open an android activity while the application is closed. See in the code below that, when I receive a notification of data from firebase, while the app is in the background, I should open an activity using MethodChannel to access java, but I get this error:
No implementation found for method openActivity on channel com.example.service/start
Application.java
package com.example.mobile;
import io.flutter.app.FlutterApplication;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback;
import io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin;
import io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService;
public class Application extends FlutterApplication implements PluginRegistrantCallback {
#Override
public void onCreate() {
super.onCreate();
FlutterFirebaseMessagingService.setPluginRegistrant(this);
}
#Override
public void registerWith(PluginRegistry registry) {
FirebaseMessagingPlugin.registerWith(registry.registrarFor("io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin"));
}
}
AndroidManifest.xml
<application
android:name="com.example.mobile.Application"
android:label="mobile"
android:icon="#mipmap/ic_launcher">
MainActivity.java
package com.example.mobile;
import androidx.annotation.NonNull;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugins.GeneratedPluginRegistrant;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin;
public class MainActivity extends FlutterActivity {
private static final String CHANNEL = "com.example.service/start";
#Override
public void configureFlutterEngine(#NonNull FlutterEngine flutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine);
new MethodChannel(flutterEngine.getDartExecutor(), CHANNEL)
.setMethodCallHandler(
(call, result) -> {
if(call.method.equals("openActivity")){
openActivity();
result.success("open activity");
}
}
);
}
void openActivity(){
Intent i = new Intent(this, SecondActivity.class);
startActivity(i);
}
}
main.dart
_firebaseMessaging.configure(
onMessage: (message) async {
//
},
onLaunch: (message) {
//
},
onResume: (message) {
//
},
onBackgroundMessage: myBackgroundMessageHandler,
);
Future<dynamic> myBackgroundMessageHandler(Map<String, dynamic> message) async {
MethodChannel channel = new MethodChannel("com.example.service/start");
if (message.containsKey('data')) {
final dynamic data = message['data'];
var open = await channel.invokeMethod("openActivity");
}
}
Where am I going wrong, and how can I make it work?
In your AndroidManifest.xml file the android:name must be android:name=".Application", And make sure that MainActivity.java and Application.java are in same folder
Related
The documentation for "How do I handle incoming intents from external applications in Flutter?" at https://flutter.dev/docs/get-started/flutter-for/android-devs#how-do-i-handle-incoming-intents-from-external-applications-in-flutter has code for the MainActivity written in Java. Yet there is no Kotlin equivalent but my Flutter project builds Kotlin files. Hence, all I need is the Kotlin equivalent for the following Java code (or at least as close to it as possible, I'm sure I can figure out the rest):
package com.example.shared;
import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.NonNull;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugins.GeneratedPluginRegistrant;
public class MainActivity extends FlutterActivity {
private String sharedText;
private static final String CHANNEL = "app.channel.shared.data";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
String action = intent.getAction();
String type = intent.getType();
if (Intent.ACTION_SEND.equals(action) && type != null) {
if ("text/plain".equals(type)) {
handleSendText(intent); // Handle text being sent
}
}
}
#Override
public void configureFlutterEngine(#NonNull FlutterEngine flutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine);
new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL)
.setMethodCallHandler(
(call, result) -> {
if (call.method.contentEquals("getSharedText")) {
result.success(sharedText);
sharedText = null;
}
}
);
}
void handleSendText(Intent intent) {
sharedText = intent.getStringExtra(Intent.EXTRA_TEXT);
}
}
(I could learn Java but zero of my work involve Java until now, so it doesn't seem efficient to learn Java just to translate this one file.)
Thanks to #che10's hint to use Android Studio's Jave to Kotlin converter (https://developer.android.com/kotlin/add-kotlin#convert), I was able to convert to a baseline that was almost compilable. The compile errors were enough clues to tell me what were the remaining touchups I had to do. The result is below:
package com.example.shared
import android.content.Intent
import android.os.Bundle
import androidx.annotation.NonNull
import io.flutter.plugin.common.MethodChannel
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugins.GeneratedPluginRegistrant
class MainActivity : FlutterActivity() {
private var sharedText: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val intent: Intent = getIntent()
val action: String? = intent.getAction()
val type: String? = intent.getType()
if (Intent.ACTION_SEND == action && type != null) {
if ("text/plain" == type) {
handleSendText(intent) // Handle text being sent
}
}
}
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine)
MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL)
.setMethodCallHandler { call, result ->
if (call.method.contentEquals("getSharedText")) {
result.success(sharedText)
sharedText = null
}
}
}
fun handleSendText(intent: Intent) {
sharedText = intent.getStringExtra(Intent.EXTRA_TEXT)
}
companion object {
private const val CHANNEL = "app.channel.shared.data"
}
}
I'm trying to follow Facebook's docs for Sharing a Sticker Asset on Android without any luck. Basically when executed the app flickers and then crash.
Could someone look at this code and point out why the app crashes after calling activity.startActivityForResult(intent, 0);? (debugging the code using logcat, I can see the code is definitely executing startActivityForResult)
package com.app.my;
import android.net.Uri;
import android.content.Intent;
import android.app.Activity;
import android.util.Log;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
public class InstagramStoriesModule extends ReactContextBaseJavaModule {
private static ReactApplicationContext reactContext;
InstagramStoriesModule(ReactApplicationContext context) {
super(context);
reactContext = context;
}
//Mandatory function getName that specifies the module name
#Override
public String getName() {
return "InstagramStories";
}
//Custom function that we are going to export to JS
#ReactMethod
public void share(ReadableMap options) {
String stickerImage = "https://www.example.com/image.jpeg";
String backgroundColor = "#000000";
Uri stickerAssetUri = Uri.parse(stickerImage);
Intent intent = new Intent("com.instagram.share.ADD_TO_STORY");
intent.setType("image/jpeg");
intent.putExtra("interactive_asset_uri", stickerAssetUri);
intent.putExtra("top_background_color", backgroundColor);
intent.putExtra("bottom_background_color", backgroundColor);
Activity activity = reactContext.getCurrentActivity();
activity.grantUriPermission("com.instagram.android", stickerAssetUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
if (activity.getPackageManager().resolveActivity(intent, 0) != null) {
activity.startActivityForResult(intent, 0);
}
}
}
i want to write some native code for printer purpose in flutter so i wrote some code for connection between the flutter and android but i am facing issue when i am trying create another java class xml in android folder. Explain me how to create new java class xml file in android folder of flutter.
flutter:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class ExamplemyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Sample Shared App Handler',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
SampleAppPage({Key key}) : super(key: key);
#override
_SampleAppPageState createState() => _SampleAppPageState();
}
class _SampleAppPageState extends State<SampleAppPage> {
static const platform = const MethodChannel('app.channel.shared.data');
String dataShared = "Restos printer working";
#override
void initState() {
super.initState();
getSharedText();
}
#override
Widget build(BuildContext context) {
return Scaffold(body: Center(child: Text(dataShared)));
}
getSharedText() async {
var sharedData = await platform.invokeMethod("getSharedText");
if (sharedData != null) {
setState(() {
dataShared = sharedData;
});
}
}
}
ANDROID:
import android.os.Bundle;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.app.FlutterActivity;
import io.flutter.plugins.GeneratedPluginRegistrant;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import android.content.Intent;
import android.os.Bundle;
import java.nio.ByteBuffer;
import io.flutter.app.FlutterActivity;
import io.flutter.plugin.common.ActivityLifecycleListener;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugins.GeneratedPluginRegistrant;
public class MainActivity extends FlutterActivity {
private String sharedText;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
Intent intent = getIntent();
String action = intent.getAction();
String type = intent.getType();
if (Intent.ACTION_SEND.equals(action) && type != null) {
if ("text/plain".equals(type)) {
handleSendText(intent); // Handle text being sent
}
}
new MethodChannel(getFlutterView(), "app.channel.shared.data").setMethodCallHandler(
new MethodCallHandler() {
#Override
public void onMethodCall(MethodCall call, MethodChannel.Result result) {
if (call.method.contentEquals("getSharedText")) {
result.success(sharedText);
sharedText = null;
}
}
});
}
void handleSendText(Intent intent) {
sharedText = intent.getStringExtra(Intent.EXTRA_TEXT);
}
}
Now i want move from mainactivity.java to another activtiy for printing
if i try to write new jav and i am getting this error;
Unhandled exception:
FileSystemException: Cannot open file, path = 'build\app.dill.track.dill' (OS Error: The system cannot find the path specified.
, errno = 3)
#0 _File.open.<anonymous closure> (dart:io/file_impl.dart:368:9)
#1 _RootZone.runUnary (dart:async/zone.dart:1379:54)
#2 _FutureListener.handleValue (dart:async/future_impl.dart:129:18)
#3 Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:642:45)
#4 Future._propagateToListeners (dart:async/future_impl.dart:671:32)
#5 Future._completeWithValue (dart:async/future_impl.dart:486:5)
#6 Future._asyncComplete.<anonymous closure> (dart:async/future_impl.dart:516:7)
#7 _microtaskLoop (dart:async/schedule_microtask.dart:41:21)
#8 _startMicrotaskLoop (dart:async/schedule_microtask.dart:50:5)
#9 _runPendingImmediateCallback (dart:isolate/runtime/libisolate_patch.dart:115:13)
#10 _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:172:5)
Unhandled exception:
SocketException: Write failed (OS Error: The pipe is being closed.
, errno = 232), port = 0
#0 _rootHandleUncaughtError.<anonymous closure> (dart:async/zone.dart:1112:29)
#1 _microtaskLoop (dart:async/schedule_microtask.dart:41:21)
#2 _startMicrotaskLoop (dart:async/schedule_microtask.dart:50:5)
#3 _runPendingImmediateCallback (dart:isolate/runtime/libisolate_patch.dart:115:13)
#4 _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:172:5)
Ihave a problem in sending image from and Android application to API . I am getting "java.lang.RuntimeException: An error occurred while executing doInBackground()" error. Please advice me on what to do. Thanks.
RecognizeConceptsActivity.java
package com.example.statistic.api.v2.activity;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.design.widget.Snackbar;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.ImageView;
import android.widget.ViewSwitcher;
import com.example.statistic.R;
import com.example.statistic.api.v2.App;
import com.example.statistic.api.v2.ClarifaiUtil;
import com.example.statistic.api.v2.adapter.RecognizeConceptsAdapter;
import java.util.Collections;
import java.util.List;
import butterknife.BindView;
import butterknife.OnClick;
import clarifai2.api.ClarifaiResponse;
import clarifai2.dto.input.ClarifaiImage;
import clarifai2.dto.input.ClarifaiInput;
import clarifai2.dto.model.ConceptModel;
import clarifai2.dto.model.output.ClarifaiOutput;
import clarifai2.dto.prediction.Concept;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
public final class RecognizeConceptsActivity extends BaseActivity {
public static final int PICK_IMAGE = 100;
// the list of results that were returned from the API
#BindView(R.id.resultsList)
RecyclerView resultsList;
// the view where the image the user selected is displayed
#BindView(R.id.image2)
ImageView imageView;
// switches between the text prompting the user to hit the FAB, and the loading spinner
#BindView(R.id.switcher)
ViewSwitcher switcher;
// the FAB that the user clicks to select an image
#BindView(R.id.fab)
View fab;
#NonNull
private final RecognizeConceptsAdapter adapter = new RecognizeConceptsAdapter();
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
protected void onStart() {
super.onStart();
resultsList.setLayoutManager(new LinearLayoutManager(this));
resultsList.setAdapter(adapter);
}
#OnClick(R.id.fab)
void pickImage() {
startActivityForResult(new Intent(Intent.ACTION_PICK).setType("image/*"), PICK_IMAGE);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != RESULT_OK) {
return;
}
switch(requestCode) {
case PICK_IMAGE:
final byte[] imageBytes = ClarifaiUtil.retrieveSelectedImage(this, data);
if (imageBytes != null) {
onImagePicked(imageBytes);
}
break;
}
}
private void onImagePicked(#NonNull final byte[] imageBytes) {
// Now we will upload our image to the Clarifai API
setBusy(true);
// Make sure we don't show a list of old concepts while the image is being uploaded
adapter.setData(Collections.<Concept>emptyList());
new AsyncTask<Void, Void, ClarifaiResponse<List<ClarifaiOutput<Concept>>>>() {
#Override
protected ClarifaiResponse<List<ClarifaiOutput<Concept>>> doInBackground(Void... params) {
// The default Clarifai model that identifies concepts in images
final ConceptModel generalModel = App.get().clarifaiClient().getDefaultModels().generalModel();
// Use this model to predict, with the image that the user just selected as the input
return generalModel.predict()
.withInputs(ClarifaiInput.forImage(ClarifaiImage.of(imageBytes)))
.executeSync();
}
#Override
protected void onPostExecute(ClarifaiResponse<List<ClarifaiOutput<Concept>>> response) {
setBusy(false);
if (!response.isSuccessful()) {
showErrorSnackbar(R.string.error_while_contacting_api);
return;
}
final List<ClarifaiOutput<Concept>> predictions = response.get();
if (predictions.isEmpty()) {
showErrorSnackbar(R.string.no_results_from_api);
return;
}
adapter.setData(predictions.get(0).data());
imageView.setImageBitmap(BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length));
}
private void showErrorSnackbar(#StringRes int errorString) {
Snackbar.make(
root,
errorString,
Snackbar.LENGTH_INDEFINITE
).show();
}
}.execute();
}
#Override
protected int layoutRes() { return R.layout.activity_recognize; }
private void setBusy(final boolean busy) {
runOnUiThread(new Runnable() {
#Override
public void run() {
switcher.setDisplayedChild(busy ? 1 : 0);
imageView.setVisibility(busy ? GONE : VISIBLE);
fab.setEnabled(!busy);
}
});
}
}
App.java
public class App extends Application {
// In a real app, rather than attaching singletons (such as the API client instance) to your Application instance,
// it's recommended that you use something like Dagger 2, and inject your client instance.
// Since that would be a distraction here, we will just use a regular singleton.
private static App INSTANCE;
#NonNull
public static App get() {
final App instance = INSTANCE;
if (instance == null) {
throw new IllegalStateException("App has not been created yet!");
}
return instance;
}
#Nullable
private ClarifaiClient client;
#Override
public void onCreate() {
INSTANCE = this;
client = new ClarifaiBuilder(getString(R.string.clarifai_api_key))
// Optionally customize HTTP client via a custom OkHttp instance
.client(new OkHttpClient.Builder()
.readTimeout(30, TimeUnit.SECONDS) // Increase timeout for poor mobile networks
// Log all incoming and outgoing data
// NOTE: You will not want to use the BODY log-level in production, as it will leak your API request details
// to the (publicly-viewable) Android log
.addInterceptor(new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
#Override
public void log(String logString) {
Timber.e(logString);
}
}).setLevel(HttpLoggingInterceptor.Level.BODY))
.build()
)
.buildSync(); // use build() instead to get a Future<ClarifaiClient>, if you don't want to block this thread
super.onCreate();
// Initialize our logging
Timber.plant(new Timber.DebugTree());
}
#NonNull
public ClarifaiClient clarifaiClient() {
final ClarifaiClient client = this.client;
if (client == null) {
throw new IllegalStateException("Cannot use Clarifai client before initialized");
}
return client;
}
}
This is the logcat error
E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
Process: com.example.statistic, PID: 3451
java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:325)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354)
at java.util.concurrent.FutureTask.setException(FutureTask.java:223)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:243)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:761)
Caused by: java.lang.IllegalStateException: App has not been created yet!
at com.example.statistic.api.v2.App.get(App.java:28)
at com.example.statistic.api.v2.activity.RecognizeConceptsActivity$1.doInBackground(RecognizeConceptsActivity.java:105)
at com.example.statistic.api.v2.activity.RecognizeConceptsActivity$1.doInBackground(RecognizeConceptsActivity.java:101)
at android.os.AsyncTask$2.call(AsyncTask.java:305)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:243)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:761)
Please advice me on what to do. Thanks
I am trying to make tests for ActivityStarter library, which is using annotation processing, but I get strange error:
An expected source declared one or more top-level types that were not present.
Expected top-level types: <[MainActivityStarter]>
Declared by expected file:
<com/example/activitystarter/MainActivityStarter.java>
The top-level types that were present are as follows:
- [ainActivityStarter] in </SOURCE_OUTPUT/ainActivityStarter.java>
When I started:
import com.google.testing.compile.JavaFileObjects
import org.junit.Test
import javax.tools.JavaFileObject
import activitystarter.compiler.ActivityStarterProcessor
import com.google.common.truth.Truth.assertAbout
import com.google.testing.compile.JavaSourceSubjectFactory
import org.junit.Assert.*
import com.google.testing.compile.JavaSourceSubjectFactory.javaSource
import com.google.testing.compile.JavaSourcesSubject
import com.google.testing.compile.JavaSourcesSubject.SingleSourceAdapter
import com.google.testing.compile.JavaSourcesSubjectFactory.javaSources
class ActivityStarterTest() {
#Test
fun simpleGenerationTest() {
val beforeProcess = "com.example.activitystarter.MainActivity" to """
import android.app.Activity;
import activitystarter.MakeActivityStarter;
#MakeActivityStarter
public class MainActivity extends Activity {}
"""
val afterProcess = "com.example.activitystarter.MainActivityStarter" to """
import android.content.Context;
import android.content.Intent;
import android.support.annotation.UiThread;
public class MainActivityStarter {
#UiThread
public static void fill(MainActivity activity) {
}
#UiThread
public static void start(Context context) {
Intent intent = new Intent(context, MainActivity.class);
context.startActivity(intent);
}
#UiThread
public static void startWithFlags(Context context, int flags) {
Intent intent = new Intent(context, MainActivity.class);
intent.addFlags(flags);
context.startActivity(intent);
}
#UiThread
public static Intent getIntent(Context context) {
Intent intent = new Intent(context, MainActivity.class);
return intent;
}
}
"""
processingComparator(beforeProcess, afterProcess)
}
fun processingComparator(beforeProcess: Pair<String, String>, afterProcess: Pair<String, String>) {
val source = JavaFileObjects.forSourceString(beforeProcess.first, beforeProcess.second)
val bindingSource = JavaFileObjects.forSourceString(afterProcess.first, afterProcess.second)
assertAbout<SingleSourceAdapter, JavaFileObject, JavaSourceSubjectFactory>(javaSource())
.that(source)
.processedWith(ActivityStarterProcessor())
.compilesWithoutWarnings()
.and()
.generatesSources(bindingSource)
}
}
Both before and after process code was taken from real code before and after process, so it should be ok. Also, in lib there is no way of cutting this first letter:
JavaFile brewJava() {
return JavaFile.builder(bindingClassName.packageName(), getActivityStarterSpec())
.addFileComment("Generated code from ActivityStarter. Do not modify!")
.build();
}
private TypeSpec getActivityStarterSpec() {
TypeSpec.Builder result = TypeSpec
.classBuilder(bindingClassName.simpleName())
.addModifiers(PUBLIC);
and:
bindingClassName = ClassName.get(packageName, className + "Starter");
Any idea how do deal with it?