I'm using expo-image-picker to allow the user to pick and take pictures. Choosing an image from the library works as expected but when using the camera, after taking the picture the app crashes.
Here is my code:
const take = async () => {
let result = await ImagePicker.launchCameraAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
quality: 1,
});
console.log(result.uri);
if (!result.cancelled) {
setImageUri(result.uri);
}
};
I think I have all the required permissions and the problem seems to occur only on older android devices with limited memory. Any ideas?
There is no good and easy solution.
What is happening is, when you launch the camera, it launches as a new Activity, leaving your app mainActivity in background.
From Android P (9) and on, the OS can kill your background activity. There is even a website just about whose implementation is worse for devs: https://dontkillmyapp.com/
Possible solutions:
Be prepared to crash. Save all states and navigation stack on local-storage, launchCamera. The app will restart, you will restore all the screen/navigation/data/etc, and get photo using the ImagePicker.getPendingResultAsync.
Change lib to expo-camera or react-native-vision-camera as they use the camera on mainActivity but needs boring reimplementation, and don' t look as good as the manufacturer native cameras.
Related
Already tried to look into all different problems here on StackOverflow with related titles, like this one. But no success.
Here is the piece of code where the problem happens:
const fetchApi = useCallback(async () => {
setIsLoading(true);
if (activePortfolioId) {
try {
const response = await getApis().portfoliosApi.getPortfolioOverviewById(
activePortfolioId
);
if (response.data && response.data?.tickers?.length) {
setItems(handleListItems(response.data.tickers));
}
} catch (error) {
Sentry.Native.captureException(error);
Sentry.Native.captureMessage('HELLO?');
Alert.alert(
'Sorry!',
'We were unable to retrieve the performance list. Please try again later.'
);
} finally {
setIsLoading(false);
}
}
}, [activePortfolioId]);
So what happens is, on iOS I have no problem at all here, either on DEV or PROD, using real device or simulator, everything works fine, never went to the catch statement. On Android, using simulator or real device with Expo, it's all fine too, even using expo start --no-dev --minify to try to reproduce the app as PROD, occurs no errors at all. I have tried everything that came on my mind, like removing pieces of the code to see if the problem stops. Like instead of calling the API, just setting the items, like this:
setItems(handleListItems(response.data.tickers)); because I also thought that the problem might be with my handler function, I also tried to just do setItems([{ OBJECT HERE }]);. The problem has just stopped once I stopped setting the items. So I also tried to check my renderItem function, tried to stop using any styled component, just what React Native provides, nothing works. Then I decided to bring Sentry to my code but even with Sentry, no issues is shown there. I open the screen, it is loading, fetches the API, then it falls in the catch block, because I see the Alert on Android and then the app crashes and go back to the splash screen frozen. The only issue that appeared on Sentry was:
Could not open URL 'https://XXXXXXX': No Activity found to handle Intent { act=android.intent.action.VIEW dat=https://XXXXXXX... flg=0x10000000 }
But strangely I have never clicked on this during the "tests" and this link just appears on the login screen, shouldn't have anything to do with the problem itself, right?
I really don't know what else I could try to do and figure out what is causing this problem, so decided to ask for help and maybe find someone who already went through something similar.
Thanks!
PS: I'm using TS too, so apparently no problems with some possible undefined or whatever.
Found the issue, it was with the Intl. Solution here.
I'm trying to develop an android app for the SDK version 30 that (when a button is clicked) starts listening to what apps are opened on the phone. If it detects the user opening Whatsapp, it is supposed to show a LockScreen activity over Whatsapp that makes you answer a math question before being able to use Whatsapp.
I know this can be done as their are apps like QualityTime or Forest that have similar features to restrict you from using certain apps, but I am a newbie when it comes to programming (probably obvious from my code) and feel totally stuck.
I have already figured out how to detect what app the user opened in the last second with code from stack overflow:
public String getCurrentApp() {
String topPackageName = "None";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
UsageStatsManager mUsageStatsManager = (UsageStatsManager) getSystemService("usagestats");
long time = System.currentTimeMillis();
List<UsageStats> stats = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000 * 1, time);
// Sort the stats by the last time used
if (stats != null) {
SortedMap<Long, UsageStats> mySortedMap = new TreeMap<Long, UsageStats>();
for (UsageStats usageStats : stats) {
mySortedMap.put(usageStats.getLastTimeUsed(), usageStats);
}
if (!mySortedMap.isEmpty())
{
topPackageName = mySortedMap.get(mySortedMap.lastKey()).getPackageName();
}
}
}
return topPackageName;
}
I have another function that is started when the user clicks the button in my app to "activate" the listening process. This function keeps checking if the user opens Whatsapp and is then supposed to display the Lockscreen activity on top:
public void startListening(View view)
{
System.out.println("Lock activated.");
while (activated) {
String currentlyRunningApp;
currentlyRunningApp = getCurrentApp();
if (currentlyRunningApp.equals("com.whatsapp"))
{
System.out.println("Whatsapp detected. Showing Lockscreen...");
Intent i = new Intent(this,LockScreen.class);
startActivity(i);
}
try {
Thread.sleep(800);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
(All of the code I have shown is in my MainActivity btw.)
I have the following permissions granted to my app:
android.permission.PACKAGE_USAGE_STATS (for the getCurrentApp() function)
android.permission.SYSTEM_ALERT_WINDOW (as suggested here)
android.permission.ACTION_MANAGE_OVERLAY_PERMISSION (although I am not sure I even need this one)
My problem is, that instead of showing the Lockscreen activity I created, it only shows a blackscreen for the user. The Lockscreen activity itself works fine if I let the user open it through a button on the mainActivity, so the issue seems to really be that I can not properly show an activity if my app is running in the background and I want to display it on top of Whatsapp.
I have tried to look through similar questions, but all of the posts on here with similar use cases seem to be very old and outdated (i.e. this or this), as the newer versions seem to have way tighter security restrictions.
I also tried to do it with a screen overlay instead of an activity (using this source), but this doesn't even give me a blackscreen - just does nothing...
I am also aware that there are probably better ways to program the whole "listening and checking for whatsapp" part - i.e. with a service instead of a while-loop or something, but I only found out about services while researching this problem and I'd like to fix the blackscreen issue first.
After lots of trial and error I figured out that the issues was indeed caused by a missing permission, but one that I could not find on any stack overflow answer related to black screen problems. On top of that, I believe it's an issue that only occurred because I used a Xiaomi device for testing.
There are currently two separate permissions for displaying screens over other apps that you will need to grant:
Display over other apps, also called Display pop-up window. This is the android.permission.ACTION_MANAGE_OVERLAY_PERMISSION that I wasn't sure was even needed. So to emphasize, I definetly do need this permission.
Display pop-up windows while running in the background. This is the permission I was missing.
After I allowed them both (which you can do under Settings > Apps > Manage Apps > Your App > Other Permissions) everything worked fine.
To direct the user directly to the settings menu where they can allow these permissions, I used the code from this stack overflow answer. This is also where I got the info that it's a xiaomi-specific "issue".
I am stuck with a functionality of the Firebase SDK (Auth package) regarding the Scenes and it's integration. Here's how they work:
1st: Loading Scene
Here, I just added the FirebaseInit code EXACTLY as suggested by Patrick, which it's only function is to call the next scene (Login/Register) once everything loads correctly.
2nd: Login/Register Scene
Here I do all the Login AND ALSO the register logic. I set up a button that alternates between the two (Activating the respective parent gameObject within the Canvas). Once the user log's in, the 3rd scene comes into play.
3rd: App's Main Screen Scene
Main Screen of the app, where the user can LOGOUT and return to the Login Scene.
Problem
I added the 'LoadSceneWhenUserAuthenticated.cs' in the 2nd Scene, and it works (kind of).
It actually does what it is supposed to. If I log in, quit the game without loging out, and open it again, it does come back directly to the 3rd scene. BUT some things are happening and they aren't supposed to.
First
When I Sign Up a user, I call the method 'CreateUserWithEmailAndPasswordAsync()'. Once it completes, it should activate the login screen and stay there, waiting for the user to fill in the password, but the 'FirebaseAuth.DefaultInstance.StateChanged' comes into play and forces the 3rd screen to be loaded, skipping several other steps that should be taken (email registration for example).
Second
As I mentioned in the end of number 1 above, if I try to log in to an account that does not have it's email verified, it works! (due to the 'LoadSceneWhenUserAuthenticated.cs' which is added in the scene). Code:
var LoginTask = auth.SignInWithEmailAndPasswordAsync(_email, _password);
LoginTask.ContinueWithOnMainThread(task =>
{
if (task.IsCanceled || task.IsFaulted)
{
Firebase.FirebaseException e =
task.Exception.Flatten().InnerExceptions[0] as Firebase.FirebaseException;
GetErrorMessage((AuthError)e.ErrorCode, warningLoginText);
return;
}
if (task.IsCompleted)
{
User = LoginTask.Result;
if (User.IsEmailVerified == true)
{
UIControllerLogin.instance.MainScreenScene();
}
else
{
warningLoginText.text = Lean.Localization.LeanLocalization.GetTranslationText($"Login/VerifyEmail");
}
I know that it's possible to fix this issue by adding an extra scene just before the login scene (as Patrick does in the youtube video) but it doesn't make any sense in my app. It would actually only harm the UX of it.
Patrick's Video:
https://www.youtube.com/watch?v=52yUcKLMKX0&t=264s
I'm glad my video helped!
My architecture won't work for every game, and I tried to boil it down to the bare minimum to get folks started. You may be able to get the functionality you want by adding an additional check in HandleAuthStateChanged:
private void HandleAuthStateChanged(object sender, EventArgs e)
{
if (_auth.CurrentUser != null && !_auth.CurrentUser.IsAnonymous && _auth.CurrentUser.IsEmailVerified)
{
SceneManager.LoadScene(_sceneToLoad);
}
}
but it does sound like, at this point, you'll want to build out a more robust registration/sign in flow that fits your use case.
If you need more help, I might suggest re-posting on the community mailing list or the subreddit. Those resources may be more better suited to discussing various pros/cons of different architectures or spitballing ideas (and feel free to link to any new posts in a comment so myself or others interested can follow along).
I'm trying to build a video calling app with Agora, I need to show acceptance screen like WhatsApp when user calling, if the app is exited i need to show calling screen when user is calling, I tried lot of thing but nothing works, I trying to do i flutter and but there is nothing much information on this,Please help me
First things first. You need to learn about some concepts before delving into your solution. Actually there isn't an out of the box solution.
You need to use a couple of things together:
Use push notifications to "wake up" your app:
https://pub.dev/packages/firebase_messaging
To start your app using push notifications refers to this post:
https://stackoverflow.com/a/48405551/4335775
Use CallKit (IOS) or ConnectionServices (Android) to show the upcoming call screen. By the day of this answer there are only a few packages to handle these things, here is one that can handle both platforms:
https://pub.dev/packages/flutter_callkeep
If you want a completely different thing and need to run some background process, there are bunch whole of things you should know first. I suggest beginning here: https://flutter.dev/docs/development/packages-and-plugins/background-processes
Here is a usefull package to work with background processes that should be constantly running:
https://pub.dev/packages/background_fetch
Currently there are two packages which provides integration for agora.io:
https://pub.dev/packages/agora_rtc_engine (for Agora Real Time Communication, vĂdeo call included)
https://pub.dev/packages/agora_rtm for real-time messaging
I hope this can help you.
You can try WorkManager plugin.
You can register an call back function to the os when the app is closed.
const myTask = "syncWithTheBackEnd";
void main() {
Workmanager.initialize(callbackDispatcher);
Workmanager.registerOneOffTask(
"1",
myTask, //This is the value that will be returned in the callbackDispatcher
initialDelay: Duration(minutes: 5),
constraints: WorkManagerConstraintConfig(
requiresCharging: true,
networkType: NetworkType.connected,
),
);
runApp(MyApp());
}
void callbackDispatcher() {
Workmanager.executeTask((task) {
switch (task) {
case myTask:
print("this method was called from native!");
break;
case Workmanager.iOSBackgroundTask:
print("iOS background fetch delegate ran");
break;
}
//Return true when the task executed successfully or not
return Future.value(true);
});
}
Maybe this can help you.
The complete article medium article
I am trying to show a large list in react native - Expo. When I lock the screen while data loading via API. App State changed from "Active" to "Inactive".
When I return to an active state, no data has been loaded. The App processes are stopped. ListEmptyComponent renders the ActivityIndicator. It is loading indefinitely. It occurs only in android build.
I tried to recall the API by AppState.
const handleAppStateChange = nextAppState => {
console.log(nextAppState);
if (nextAppState === 'active') {
console.log(JSON.stringify(Store.apiCall));
// "Store.apiCall" has data about last API Call and its status.
if (Store.apiCall.status === codes.PENDING || Store.apiCall.status === codes.ERROR) {
api(Store.apiCall.payload);
}
}
setAppState(nextAppState);
};
Still it doesn't works..
This happening because of the battery optimization features of newer Android versions. The only fix would be to ask the user to disable the battery optimization for your app by redirecting them to your app settings or you can use a node package like this one:
https://www.npmjs.com/package/react-native-disable-battery-optimizations
Also, if you dont want your device to sleep if its in active state you can use something like this:
https://www.npmjs.com/package/react-native-keep-awake
Hope this helps :)