I want to make a screen page that can be navigated in the contact list on my phone. so I made a native module for get contact, It worked but for android 10 and below. For android 11 he can't run. The function I created can't get contact data.I've made sure all the permissions are there. Below is the code I made
const getChooseContact = () => {
const { ContactsWrapper } = NativeModules;
ContactsWrapper.getContact()
.then((contact) => {
setPhoneNumber(contact.phoneNumber);
})
.catch((error) => {
console.log(error);
});
};
const requestMediaPermission = async () => {
try {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.READ_CONTACTS,
);
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
getChooseContact();
} else {
setErrorMessage('Access media permission denied');
}
} catch (err) {
console.log(err);
}
};
This is majorly because in API 30 and above we can no-longer interact with external modules without specifically being allowed the interaction.
This can happen in two ways one using the <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" /> inside the androidmanifest.xml though this is discouraged since it can have your app rejected Read this kindly https://support.google.com/googleplay/android-developer/answer/10158779#zippy=%2Cpermitted-uses-of-the-query-all-packages-permission
to fix your issue
inside build.gradle under android update class paths to this :
classpath 'com.android.tools.build:gradle:3.5.4' this allows for the next step to be recognised during bundling otherwise your will get an error
inside androidmanifest.xml before the application tag add this
<queries>
<!-- Browser -->
<intent android:label="View Contact">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.item/person" android:host="contacts" />
</intent>
</queries>
Related
Is there a good way to do display a maintenance page when visiting any route of my SvelteKit website?
My app is hosted on Vercel, for those who want to know.
What I've tried so far:
Set an environment variable called MAINTENANCE_MODE with a value 1 in Vercel.
For development purposes I've set this in my .env file to VITE_MAINTENANCE_MODE and called with import.meta.env.VITE_MAINTENANCE_MODE.
Then inside +layout.server.js I have the following code to redirect to /maintenance route
import { redirect } from "#sveltejs/kit";
export async function load({ url }) {
const { pathname } = url;
// Replace import.meta.env.VITE_MAINTENANCE_MODE with process.env.MAINTENANCE_MODE in Production
if (import.meta.env.VITE_MAINTENANCE_MODE == 1) {
if (pathname == "/maintenance") return;
throw redirect(307, "/maintenance");
} else {
if (pathname == "/maintenance") {
throw redirect(307, "/");
};
};
};
What I've also tried is just throwing an error in +layout.server.js with the following:
import { error } from "#sveltejs/kit";
export async function load() {
if (import.meta.env.VITE_MAINTENANCE_MODE == 1) {
throw error(503, "Scheduled for maintenance");
};
};
However this just uses SvelteKit's static fallback error page and not +error.svelte. I've tried creating src/error.html in the hope to create a custom error page for +layout.svelte but couldn't get it to work.
I would like to use a custom page to display "Down for maintenance", but I don't want to create an endpoint for every route in my app to check if the MAINTENANCE_MODE is set to 1.
Any help is appreciated
You could use a handle server hook, e.g. src/hooks.server.ts:
import { env } from '$env/dynamic/private';
import type { Handle } from '#sveltejs/kit';
export const handle: Handle = async ({ event, resolve }) => {
if (env.MAINTENANCE_MODE == '1' && event.routeId != '/maintenance')
return new Response(undefined, { status: 302, headers: { location: '/maintenance' } });
// <other logic>
// Default response
return await resolve(event);
}
And on the maintenance page you can prevent all further navigation:
import { beforeNavigate } from '$app/navigation';
beforeNavigate(async ({ cancel }) => {
cancel();
});
(Possibly add some periodic checks via fetch calls to navigate elsewhere once the site is back online.)
You can also use +layout.ts to hook up for the maintenance mode. You can even make this conditional for some parts of the site (have frontpage still up and running).
Here is the trick we use:
import type { LayoutLoad } from './$types';
import { chainsUnderMaintenance } from '$lib/config';
import { error } from '#sveltejs/kit';
export const load: LayoutLoad = ({ params }) => {
// Check chain maintenance status; if under maintenance, trigger error (see +error.svelte)
const chainName = chainsUnderMaintenance[<string>params.chain];
if (chainName) {
throw error(503, `Chain under maintenance: ${chainName}`);
}
};
Background
Hey everyone,
I am building a group bicycle riding app that shows users where they are in a map in real time.
Short app explanation is: You go out with friends for hiking, cycling, etc, and you want to know where you and your friends are in real time.
The only requirement is a foreground location access when the app is in use, no more. Then, I want to update each member's location using Location.startLocationUpdatesAsync().
Sample Code
import React from 'react'
import { Text, TouchableOpacity } from 'react-native'
import * as Location from 'expo-location';
import * as TaskManager from 'expo-task-manager';
const LOCATION_TASK_NAME = 'background-location-task';
TaskManager.defineTask(LOCATION_TASK_NAME, ({ data, error }) => {
if (error) {
console.log(error);
return;
}
if (data) {
const { locations } = data;
console.log(data);
}
});
const requestPermissions = async () => {
const { status } = await Location.requestForegroundPermissionsAsync();
if (status === 'granted') {
await Location.startLocationUpdatesAsync(LOCATION_TASK_NAME, {
accuracy: Location.Accuracy.Balanced,
});
}
};
const HomeScreen = () => {
return (
<TouchableOpacity onPress={requestPermissions}>
<Text>Enable Location</Text>
</TouchableOpacity>
)
}
export default HomeScreen
Problem
Foreground permission (Location.requestForegroundPermissionsAsync()) popup appears on the screen with no problem. Access is granted. When run, this error comes up:
Error: Not authorized to use background location services.
The problem is I need a background permission to be able to update location information in real time. When I try to request for background permission with requestBackgroundPermissionsAsync(), this error comes up:
Error: You need to add `ACCESS_BACKGROUND_LOCATION` to the AndroidManifest.
I don't know if AndroidManifest file should be changed with expo apps, but I added permissions key to android inside app.json file like so:
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#FFFFFF"
},
"permissions":[
"ACCESS_FINE_LOCATION",
"ACCESS_BACKGROUND_LOCATION",
"ACCESS_COARSE_LOCATION"
]
}
I have looked into an open issue on expo's github repo. It does not seem to help. I have 0 intention of putting my app on Play Store.
Questions
Do I need to go through google's verification process by filling up the form, taking video of my app which is under development and won't ever be put on Play Store?
Am I even allowed to test the feature before even thinking about releasing it?
What approach should I take to just get location updates?
Is there any workaround?
What I tried
requesting for Background Location acess by Location.requestBackgroundPermissionsAsync()
putting permissions key inside app.json:
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#FFFFFF"
},
"permissions":[
"ACCESS_FINE_LOCATION",
"ACCESS_BACKGROUND_LOCATION",
"ACCESS_COARSE_LOCATION"
]
}
checking for background permission and asking for it if not granted:
const { fr_status } = await Location.requestBackgroundPermissionsAsync();
if (fr_status === 'granted' && await Location.isBackgroundLocationAvailableAsync()) {
await Location.startLocationUpdatesAsync(LOCATION_TASK_NAME, {
accuracy: Location.Accuracy.Balanced,
});
} else {
const {bg_status} = await Location.requestBackgroundPermissionsAsync();
if (bg_status === 'granted') {
await Location.startLocationUpdatesAsync(LOCATION_TASK_NAME, {
accuracy: Location.Accuracy.Balanced,
});
}
}
Development environment
Managed app built with expo 4.13.0.
Android Emulator 31.1.4
Android SDK Platform Tools 31.0.3
Android 10.0 Q, API level 29, revision 5
Node.js v16.13.0
npm version 8.1.0
react-native version 0.64.3
Windows 10 Pro version 20H2
I added admob interstitial to my android app.
The app and interstitial are working fine on emulator, with TestID and a real ID. But on real devices it is not showing any ad, and there is no crashes or errors.
Could you please help me to find what might be the reason? Here is my code :
import admob, { InterstitialAd, TestIds, AdEventType } from '#react-native-firebase/admob';
...
showAdss(){
const idx = 'ca-app-pub-3....10';
const interstitial = InterstitialAd.createForAdRequest(idx, {
requestNonPersonalizedAdsOnly: true,
keywords: ['fashion', 'clothing']
});
interstitial.onAdEvent((type) => {
if (type === AdEventType.LOADED) {
interstitial.show();
}
});
and from manifest file :
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
...
I am using the plugin nativescript-geolocation, and I'm trying to record user locations while the app is suspended. I am making a navigation style app that needs to be able to monitor the user's location while the app is not opened. For example, I start my navigation, then I press 'home' on the device and open another app; I would like to record their geolocation in the background.
I have tried following this, but the location only runs while the app is open. If the app gets suspended, console logs do not appear to happen when the device is moved. I also tried saving locations into an array and then console logging them when the app is resumed, this only printed out the first location segment.
background-service.js
const geolocation = require("nativescript-geolocation");
const Accuracy = require("tns-core-modules/ui/enums").Accuracy;
const application = require("tns-core-modules/application");
const device = require("tns-core-modules/platform");
var watchID;
function clearWatch() {
if (watchID) {
geolocation.clearWatch(watchID);
watchID = null;
}
}
function startWatch() {
console.log("starting watch??");
clearWatch();
watchID = geolocation.watchLocation(
function (loc) {
console.log("repeat?");
if (loc) {
console.log("Background location: " + loc.latitude + ", " + loc.longitude);
}
},
function (err) {
console.log(err);
}, {
desiredAccuracy: Accuracy.high,
updateDistance: 5,
updateTime: 1000
}
);
}
application.on(application.exitEvent, clearWatch);
if (application.android) {
android.app.job.JobService.extend("com.oa.location.BackgroundService26", {
onStartJob() {
console.log("service onStartJob");
startWatch();
return true;
},
onStopJob(jobParams) {
console.log("service onStopJob");
this.jobFinished(jobParams, false);
clearWatch();
return false;
},
});
}
in home-page.js
application.on(application.suspendEvent, args => {
// background recording segment
if (application.android) {
var context = utils.ad.getApplicationContext();
var component = new android.content.ComponentName(context, com.oa.location.BackgroundService26.class);
var builder = new android.app.job.JobInfo.Builder(1, component);
builder.setRequiredNetworkType(android.app.job.JobInfo.NETWORK_TYPE_ANY);
//builder.setPeriodic(30);
const jobScheduler = context.getSystemService(android.content.Context.JOB_SCHEDULER_SERVICE);
service = jobScheduler.schedule(builder.build());
console.log(`Job Scheduled: ${jobScheduler.schedule(builder.build())}`);
// var intent = new android.content.Intent(context, com.oa.location.BackgroundService26.class);
// context.startService(intent);
}
console.log("suspended");
});
application.on(application.resumeEvent, args => {
if (args.android) {
//geolocation.clearWatch(watchID);
console.log("resumed");
// remove background recording
var context = utils.ad.getApplicationContext();
const jobScheduler = context.getSystemService(android.content.Context.JOB_SCHEDULER_SERVICE);
jobScheduler.cancel(service);
console.log("Canceled " + service);
service = null;
}
});
in AndroidManifest.xml
<application android:usesCleartextTraffic="true" android:name="com.tns.NativeScriptApplication" android:allowBackup="true" android:icon="#drawable/icon" android:label="#string/app_name" android:theme="#style/AppTheme">
<meta-data android:name="firebase_crashlytics_collection_enabled" android:value="true" />
<service android:name="com.oa.location.BackgroundService26" android:permission="android.permission.BIND_JOB_SERVICE" android:enabled="true" android:exported="false">
</service>
<activity android:name="com.tns.NativeScriptActivity" android:label="#string/title_activity_kimera" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout|locale|uiMode" android:theme="#style/LaunchScreenTheme" android:screenOrientation="portrait">
<meta-data android:name="SET_THEME_ON_LAUNCH" android:resource="#style/AppTheme" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.tns.ErrorReportActivity" />
</application>
What I expect to happen is when the user presses their device's home button to put the app in suspension mode, the background service runs and collects geolocation updates.
Since you are focusing only on BackgroundService26 I assume you are testing with Android 8 or later, in which case I think you missed setOverrideDeadline
I am trying to make 2 react app versions communicate with each other (react 16 to 15). I want to pass a message from my react16 app to my react15 in a one-way manner. I did not find it viable to upgrade the old app to a newer version since I only need something to work for the meantime while we develop a newer version.
So what my react 16 app does basically is it already sends a message to a chrome extension and the extension will, in turn, return a dataUrl. An the dataUrl would then be rendered to a canvas then after editing the image it would send it to firebase using axios for storage. Firebase will then have a response that I would want to be sent to the react 15 app using an event listener.
What I tried is that when the image is successfully sent to the database the react 16 app will do a window.postMessage(). The older app has an eventlistener on componentDidMount() which supposedly should catch the message.
When I make this run It won't work though. The postMessage is okay but it seems like the eventListener isn't catching it.
Any help would be appreciated. Thanks!
React 16 app
ImageContainer.js
...
axios.post('/screenshots.json', submittedImage)
.then(response => {
this.setState({ showPrompt: false })
response.status === 200 ? this.props.notify(true, "Screenshot Saved! ") : this.props.notify(false)
this.props.storeImageToArrayHandler(submittedImage)
let firebaseId = response.data.name // This will be used for single querying the image from firebase
let feedBackButton = document.getElementById('feedback-button');
feedBackButton.click();
var data = { type: "FROM_REACT16", text: "Enter Image ID" };
console.log("[ImageContainer] Sending Message...")
window.postMessage(data, "*");
this.setState({ showImageContainer: false })
})
.catch(error => {
this.setState({ showPrompt: false })
this.props.notify(false, "Unable to save Screenshot. " + error)
this.props.storeImageToArrayHandler("")
})
...
React 15 app
MainContainer.js
...
componentDidMount() {
console.log("[componentDidMount] MainContainer.js")
window.addEventListener("image_interceptor", function (event) { //listen for messages from react app
console.log("[MainContainer] Listening for messages...")
if (event.data.type && (event.data.type === "FROM_REACT16")) {
console.log('I got the message');
}
return true;
});
window.mainContainer = {
addStateValidator: this.addStateValidator,
};
this.props.start();
}
...
index.html
...
<BODY>
<div style=" width: 100%; height:100%; position: absolute;; top:0; left:0; bottom:0; right:0;">
<div id="notification" style="display:inline;">
<p>Extension not detected.
You can download the extension here
.
</p>
</div>
</div>
<div id="root"></div> //REACT 15
<div id="screenshot"></div> //REACT 16
<script src="feedback/feedback-main.js" type="text/javascript" charset="utf-8"></script>
<script src="feedback/bundle.js" type="text/javascript" charset="utf-8"></script>
</BODY>
</HTML>