React-native fbsdk-next asks just for public_profile permission - react-native

I have next issue: my react-native app doesn't ask fb about all permissions from list, just about public_profile permission. System iOS.
My code is:
LoginManager.logInWithPermissions(['public_profile', 'user_friends', 'user_posts', 'email']).then(
(result) => {
if (result.isCancelled) {
alert('Login was cancelled')
} else {
console.log("RESULT_IS", result)
AccessToken.getCurrentAccessToken().then((data) => {
const accessToken = data.accessToken.toString();
const userID = data.userID.toString();
});
Profile.getCurrentProfile().then((data) => {
console.log('DATA', data);
})
}
},
);
console.log('DATA', data) shows that imageURL, userID and name has a value, and email, firstName, lastName, middleName are null.
console.log("RESULT_IS", result) shows RESULT_IS {"declinedPermissions": [], "grantedPermissions": ["public_profile"], "isCancelled": false}
So I am using Profile.getCurrentProfile() to get additional data from fb (for example email). To do that I asked fb about additional permissions adding them to LoginManager.logInWithPermissions(). As I understood my app doesn't ask about fb all permissions just about public_profile. Why does it happened and how can I fix it?

I had the same issue too.
On Android, in the path below
node_modules/react-native fbsdk-next/android/src/main/java/com/facebook/reactnative/androidsdk/FBProfileModule.java
You can import profile information right away by editing the file as shown below.
I also referenced other people's content.
So have a nice day!
FBProfileModule.java
package com.facebook.reactnative.androidsdk;
import com.facebook.Profile;
import com.facebook.ProfileTracker; // add
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.module.annotations.ReactModule;
import androidx.annotation.NonNull;
/**
* This is a {#link NativeModule} that allows JS to use FBSDKProfile info of the current logged user.
+ * current logged user // add
*/
#ReactModule(name = FBProfileModule.NAME)
public class FBProfileModule extends ReactContextBaseJavaModule {
public static final String NAME = "FBProfile";
private ProfileTracker mProfileTracker; // add
public FBProfileModule(ReactApplicationContext reactContext) {
super(reactContext);
}
#NonNull
#Override
public String getName() {
return NAME;
}
/**
* Get the current logged profile.
* #param callback Use callback to pass the current logged profile back to JS.
*/
#ReactMethod
public void getCurrentProfile(Callback callback) {
//Return the profile object as a ReactMap.
// add
if (Profile.getCurrentProfile() == null) {
mProfileTracker = new ProfileTracker() {
#Override
protected void onCurrentProfileChanged(Profile oldProfile, Profile currentProfile) {
callback.invoke(Utility.profileToReactMap(currentProfile));
mProfileTracker.stopTracking();
}
};
} else {
callback.invoke(Utility.profileToReactMap(Profile.getCurrentProfile()));
}
// remove
// callback.invoke(Profile.getCurrentProfile() == null
// ? null
// : Utility.profileToReactMap(Profile.getCurrentProfile()));
}
}

Facebook provides public profile by default if you want anything else you will have to add it by visiting your app in facebook developer console.
Go to your app
Open app Review
In app review open Permissions and Features
In Permissions and Features you can see multiple options
Select your desired permission and try again you will get that value as well.
I hope it helps you.

Related

React-native share on discord

I'm implementing a feature on a project where we want users to be able to share a post on discord. Implementing sharing on facebook or twitter was easy using https://react-native-community.github.io/react-native-share/docs/share-single
But there's no support for discord on shareSingle and I don't want a share button calling for Native Share menu which could link to discord, I want a discord icon redirecting directly to discord. But I can't even find a way to open discord app with url schemas or universal link to trigger the app (discord:// or discord://discord or discordapp:// ...).
I tried to find a way to get access to native sharing in order to open discord sharing singly, but couldn't find a way.
Does anyone implemented discord sharing and have any tips on how to achieve that in react-native ?
You can make a fork the project and add this files:
android/src/main/java/cl/json/social/DiscordShare.java
package cl.json.social;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import java.io.File;
import android.os.Environment;
import android.net.Uri;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReadableMap;
public class DiscordShare extends SingleShareIntent {
private static final String PACKAGE = "com.discord";
private static final String PLAY_STORE_LINK = "https://play.google.com/store/apps/details?id=com.discord";
public DiscordShare(ReactApplicationContext reactContext) {
super(reactContext);
}
#Override
public void open(ReadableMap options) throws ActivityNotFoundException {
super.open(options);
// extra params here
this.openIntentChooser();
}
#Override
protected String getPackage() {
return PACKAGE;
}
#Override
protected String getDefaultWebLink() {
return null;
}
#Override
protected String getPlayStoreLink() {
return PLAY_STORE_LINK;
}
}
Edit android/src/main/java/cl/json/RNShareModule.java
package cl.json;
// ...
import cl.json.social.DiscordShare;
public class RNShareModule extends ReactContextBaseJavaModule implements ActivityEventListener {
// ...
private enum SHARES {
facebook,
generic,
pagesmanager,
twitter,
whatsapp,
instagram,
instagramstories,
googleplus,
email,
pinterest,
messenger,
snapchat,
sms,
linkedin,
discord; // ADDED
public static ShareIntent getShareClass(String social, ReactApplicationContext reactContext) {
SHARES share = valueOf(social);
switch (share) {
case generic:
return new GenericShare(reactContext);
case facebook:
return new FacebookShare(reactContext);
case pagesmanager:
return new FacebookPagesManagerShare(reactContext);
case twitter:
return new TwitterShare(reactContext);
case whatsapp:
return new WhatsAppShare(reactContext);
case instagram:
return new InstagramShare(reactContext);
case instagramstories:
return new InstagramStoriesShare(reactContext);
case googleplus:
return new GooglePlusShare(reactContext);
case email:
return new EmailShare(reactContext);
case pinterest:
return new PinterestShare(reactContext);
case sms:
return new SMSShare(reactContext);
case snapchat:
return new SnapChatShare(reactContext);
case messenger:
return new MessengerShare(reactContext);
case linkedin:
return new LinkedinShare(reactContext);
case discord:
return new DiscordShare(reactContext); // ADDED
default:
return null;
}
}
};
}
// ...
Finally edit index.js
//...
class RNShare {
//...
static Social = {
FACEBOOK: NativeModules.RNShare.FACEBOOK || 'facebook',
FACEBOOK_STORIES: NativeModules.RNShare.FACEBOOK_STORIES || 'facebook-stories',
PAGESMANAGER: NativeModules.RNShare.PAGESMANAGER || 'pagesmanager',
TWITTER: NativeModules.RNShare.TWITTER || 'twitter',
WHATSAPP: NativeModules.RNShare.WHATSAPP || 'whatsapp',
INSTAGRAM: NativeModules.RNShare.INSTAGRAM || 'instagram',
INSTAGRAM_STORIES: NativeModules.RNShare.INSTAGRAM_STORIES || 'instagramstories',
GOOGLEPLUS: NativeModules.RNShare.GOOGLEPLUS || 'googleplus',
EMAIL: NativeModules.RNShare.EMAIL || 'email',
PINTEREST: NativeModules.RNShare.PINTEREST || 'pinterest',
LINKEDIN: NativeModules.RNShare.LINKEDIN || 'linkedin',
SMS: NativeModules.RNShare.SMS || 'sms',
DISCORD: NativeModules.RNShare.DISCORD || 'discord', // ADDED
};
// ...
}
In your project use:
Share.shareSingle({
title: 'test',
message: 'hola mundo',
url: 'https://json.cl',
social: Share.Social.DISCORD,
})
.then((res) => {
console.log(res);
})
.catch((err) => {
err && console.log(err);
});
Result:

How to migrate data from react native asyncstorage to flutter?

I'm looking to migrate a react native app to flutter, so far everything is good. But I have to migrate user data stored in react native asyncstorage and I don't even know where to start. Does anyone can guide me in the right direction?
i did the same thing, and ended up making a simple helper class with flutter_secure_storage:
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'dart:async';
class LocalStorage {
final storage = new FlutterSecureStorage();
void writeValue(String key, String value) {
storage.write(key: key, value: value);
}
void deleteValue(String key) async {
await storage.delete(key: key);
}
Future readValue(String key) async {
String value = await storage.read(key: key);
return value;
}
}
which you'd then use in a screen like so:
final _storage = new LocalStorage();
Future _getValue() async {
String _someValue = await _storage.readValue('someKey');
}
After facing the same problem today, I've come up with a solution for iOS. I don't have an issue on Android so unfortunately I don't have a solution for Android either.
Basically the RN AsyncStorage package creates a folder that includes a manifest.json. This folder is stored in the Documents directory of your app. My approach is to simply load that file and return the key.
Future<String> getReactNativeAsyncStorageValue(String key) async {
if (!Platform.isIOS) return null;
try {
Directory directory = await getApplicationDocumentsDirectory();
Directory rctStorageDirectory = Directory(directory.path + '/RCTAsyncLocalStorage_V1');
File manifest = File(rctStorageDirectory.path + "/manifest.json");
if (await rctStorageDirectory.exists() && await manifest.exists()) {
try {
String data = await rootBundle.loadString(manifest.path);
if (data?.isNotEmpty ?? false) {
var jsonData = json.decode(data);
if (jsonData is Map) {
String value = jsonData[key];
if (value != null) {
return value;
}
}
}
} catch (error) {
print(error);
}
}
} catch(error){
print(error);
}
return null;
}
To add on to the answer provided by #Florian on iOS, I somehow managed to get it working on Android.
First, add sqlfite
Then use it to open the database, then query the table
final db = await openDatabase('RKStorage');
final existingData = await db.query('catalystLocalStorage');
Note, this is only tested on React Native 0.64.0

How to implement push notification and file upload and download with webview?

I was wanting to know how my app can alert users that they have a notification on my forum? Also I'd like to know how I can allow users to upload and download files to and from my forum within the app. I'm using webview and not sure if my code is up to date. I'm a noob when it comes to this stuff.
Here's my code:
package technologx.technologx;
/**
* Created by Technologx on 12/22/15
* ©2015 Technologx All Rights Reserved
* http://technologx.fulba.com
*/
import android.os.Build;
import android.os.Bundle;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.webkit.CookieSyncManager;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import com.google.android.gms.appindexing.Action;
import com.google.android.gms.appindexing.AppIndex;
import com.google.android.gms.common.api.GoogleApiClient;
#SuppressLint("SetJavaScriptEnabled")
public class MainActivity extends Activity {
/**
* ATTENTION: This was auto-generated to implement the App Indexing API.
* See https://g.co/AppIndexing/AndroidStudio for more information.
*/
private GoogleApiClient client;
private WebView webView;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// If the Android version is lower than Jellybean, use this call to hide
// the status bar.
if (Build.VERSION.SDK_INT < 16) {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
// Adds Progress Bar Support
this.getWindow().requestFeature(Window.FEATURE_PROGRESS);
// Makes Progress Bar Visible
getWindow().setFeatureInt(Window.FEATURE_PROGRESS, Window.PROGRESS_VISIBILITY_ON);
// Use forum.xml as webview layout
setContentView(R.layout.activity_main);
webView = (WebView) findViewById(R.id.webView);
webView.getSettings().setJavaScriptEnabled(true);
// Adds Zoom Control (You may not need this)
webView.getSettings().setSupportZoom(true);
// Enables Multi-Touch. if supported by ROM
webView.getSettings().setBuiltInZoomControls(true);
// Change to your own forum url
webView.loadUrl("http://technologx.96.lt/");
webView.setWebViewClient(new WebViewClient() {
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// Loads only your forum domain and no others!
if (url.contains("technologx.96.lt") == true) {
view.loadUrl(url);
// Adds Progress Bar Support
super.onPageStarted(view, url, null);
findViewById(R.id.progressbar).setVisibility(View.VISIBLE);
// If they are not your domain, use browser instead
} else {
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(i);
}
return true;
}
#Override
public void onPageFinished(WebView view, String url) {
// Removes Progress Bar
findViewById(R.id.progressbar).setVisibility(View.GONE);
// Adds Cookies. Yummy!
CookieSyncManager.getInstance().sync();
}
});
// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
client = new GoogleApiClient.Builder(this).addApi(AppIndex.API).build();
}
#Override
public void onBackPressed() {
// Enables going back history
if (webView.copyBackForwardList().getCurrentIndex() > 0) {
webView.goBack();
} else {
// Your exit alert code, or alternatively line below to finish
// Finishes forum activity
super.onBackPressed();
}
}
#Override
public void onStart() {
super.onStart();
// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
client.connect();
Action viewAction = Action.newAction(
Action.TYPE_VIEW, // TODO: choose an action type.
"Main Page", // TODO: Define a title for the content shown.
// TODO: If you have web page content that matches this app activity's content,
// make sure this auto-generated web page URL is correct.
// Otherwise, set the URL to null.
Uri.parse("http://host/path"),
// TODO: Make sure this auto-generated app deep link URI is correct.
Uri.parse("android-app://technologx.technologx/http/host/path")
);
AppIndex.AppIndexApi.start(client, viewAction);
}
#Override
public void onStop() {
super.onStop();
// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
Action viewAction = Action.newAction(
Action.TYPE_VIEW, // TODO: choose an action type.
"Main Page", // TODO: Define a title for the content shown.
// TODO: If you have web page content that matches this app activity's content,
// make sure this auto-generated web page URL is correct.
// Otherwise, set the URL to null.
Uri.parse("http://host/path"),
// TODO: Make sure this auto-generated app deep link URI is correct.
Uri.parse("android-app://technologx.technologx/http/host/path")
);
AppIndex.AppIndexApi.end(client, viewAction);
client.disconnect();
}
}

Customize login in Grails Spring Security plugin

I have an application where the login should include an organization number, so the login needs to be username + password + organization number.
Sample case: If the username + password matches with an existing user, I need to check if that user has the organization id. If not, the login should fail.
I saw that the login form from spring security plugin submits to /app/j_spring_security_check but couldn't find where that is actually implemented.
Also I'm not sure if touching that is the right way of implementing this custom login.
My question is where / how to customize the login action? (to make it fail on the case I described above).
We can do this by overriding the filter UserNamePasswordAuthenticationFilter and provide our custom attemptAuthentication.
So, go to DefaultSecurityConfig.groovy file (inside plugins). See tree diagram below:
target
|-work
|-plugins
|-spring-security-core-2.0-RC5
|-conf
|-DefaultSecurityConfig.groovy
In DefaultSecurityConfig.groovy under apf closure we specify filterProcessUrl which we can override in grails application's Config.groovy like we do for other properties (e.g. rejectIfNoRule)
grails.plugin.springsecurity.apf.filterProcessesUrl="your url"
Now we understood how it checks for authentication.Let's customise it own way by overriding the method attemptAuthentication of filter named UsernamePasswordAuthenticationFilter. For example, see below(also, go through the inline comments added there)
package org.springframework.security.web.authentication;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.util.Assert;
public class CustomUsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "j_username";
public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "j_password";
/** #deprecated */
#Deprecated
public static final String SPRING_SECURITY_LAST_USERNAME_KEY = "SPRING_SECURITY_LAST_USERNAME";
private String usernameParameter = "j_username";
private String passwordParameter = "j_password";
private String organisationParameter = 'j_organisation'
private boolean postOnly = true;
public UsernamePasswordAuthenticationFilter() {
super("/j_spring_security_check");
}
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if(this.postOnly && !request.getMethod().equals("POST")) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
} else {
String username = this.obtainUsername(request);
String password = this.obtainPassword(request);
String password = this.obtainOrganisation(request);
//regular implementation in spring security plugin /**
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
this.setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
**/
//Your custom implementation goes here(Authenticate on the basis of organisation as well). Here you need to customise authenticate as per your requirement so that it checks for organisation as well.
}
protected String obtainOrganisation(HttpServletRequest request) {
return request.getParameter(this.organisationParameter);
}
protected String obtainPassword(HttpServletRequest request) {
return request.getParameter(this.passwordParameter);
}
protected String obtainUsername(HttpServletRequest request) {
return request.getParameter(this.usernameParameter);
}
protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) {
authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
}
public void setUsernameParameter(String usernameParameter) {
Assert.hasText(usernameParameter, "Username parameter must not be empty or null");
this.usernameParameter = usernameParameter;
}
public void setPasswordParameter(String passwordParameter) {
Assert.hasText(passwordParameter, "Password parameter must not be empty or null");
this.passwordParameter = passwordParameter;
}
public void setPostOnly(boolean postOnly) {
this.postOnly = postOnly;
}
public final String getUsernameParameter() {
return this.usernameParameter;
}
public final String getPasswordParameter() {
return this.passwordParameter;
}
}
Hence, it's more of a overriding task in terms of spring security.
To get more clearer idea about same read this nice link for java
and
for grails read this
Hope it helps.
These blogs gives a more detailed idea of the same requirements.

SQLite android login and register

From the previous question I asked, I am still having the same question. I do not know how to use database (SQLite) to 'sync' with my application to log in or register
package log1.log2;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class Login extends Activity {
UserDB db = new UserDB(this);
/** Called when the activity is first created. */
private EditText etUsername;
private EditText etPassword;
private Button btnLogin;
private Button btnRegister;
private TextView lblResult;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Get the EditText and Button References
etUsername = (EditText)findViewById(R.id.usernametxt);
etPassword = (EditText)findViewById(R.id.passwordtxt);
btnLogin = (Button)findViewById(R.id.btnLogin);
btnRegister = (Button)findViewById(R.id.btnRegister);
lblResult = (TextView)findViewById(R.id.msglbl);
//Cursor c = (Cursor) db.getAllTitles();
//Button btnArrival = (Button) findViewById(R.id.btnRegister);
//btnArrival.setOnClickListener(this);
// Set Click Listener
btnRegister.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent intent=new Intent(Login.this,Register.class);
startActivity(intent);
}
});
btnLogin.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
db.open();
// Check Login
String username = etUsername.getText().toString();
String password = etPassword.getText().toString();
if(username.equals("select username from Users")){
if(password.equals("select password from users where username = username"))
{
Intent intent=new Intent(Login.this,Test.class);
startActivity(intent);
}
else
{
lblResult.setText("Wrong password");
}
} else {
lblResult.setText("Username does not exist. Please register.");
}
db.close();
}
});
}
}
Should I use the 'select' 'from' 'where' statement? Or there is another way?
Where you have
username.equals("select username from Users")
you are actually testing if what the user entered is literally the same object (which it is not). To authenticate against a local database of Users, you would want to try something more like this:
Cursor c = db.rawQuery("SELECT username FROM Users WHERE username='?' AND password='?'", new String[] {username, password});
if(c.moveToFirst()) {
// at least one row was returned, this should signal success
} else {
// authentication failed
}
Where 'db' is the SQLiteDatabase object you are working with. If you need any kind of security, I would also hash the password before you store it in the database!