I implemented the Facebook App Invites feature into my app. Sending and receiving works fine in my app, but the Facebook user that received the invite on his Android app doesn't receive neither push notification or general notification as specified here. It only shows up in the App Invites section.
Does anyone know what can I do in order to show a Facebook notification?
Facebook SDK 4.20
Invite sending
private void initFbInvite(final CallbackManager callbackManager, final View inviteButton){
Map<AppLinksManager.QueriesKeys, String> queries = new HashMap<>();
queries.put(AppLinksManager.QueriesKeys.SENDER, UserManager.getInstance().getUser().getId());
final Uri appLink = AppLinksManager.generateAppLink(AppLinksManager.Endpoint.FB_INVITE, queries);
StorageReference previewImageUrlRef = mController.getStorageReference().child("applink-images/fb-invite.png");
previewImageUrlRef.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
final AppInviteContent inviteContent = new AppInviteContent.Builder()
.setApplinkUrl(appLink.toString())
.setPreviewImageUrl(uri.toString())
.build();
final AppInviteDialog appInviteDialog = new AppInviteDialog(ExploreFragment.this);
appInviteDialog.registerCallback(callbackManager, new FacebookCallback<AppInviteDialog.Result>() {
#Override
public void onSuccess(AppInviteDialog.Result result) {
Log.d(TAG, "FB invitation send successfully");
}
#Override
public void onCancel() {
Log.e(TAG, "FB invitation cancelled");
}
#Override
public void onError(FacebookException error) {
Log.e(TAG, "FB invitation error");
}
});
inviteButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
appInviteDialog.show(inviteContent);
}
});
}
});
}
Custom App Link url used for this AppInviteContent
https://stellarscepter.com/clecs/fb-invite?sender=PsF6qaJPLKVnOjxr2Ufzs5cSVTZ2
index.html (stored in clecs/fb-invite folder on the server) for App Link metadata
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<!-- Facebook App Link meta -->
<meta property="al:android:url" content="clecs://fb-invite" />
<meta property="al:android:app_name" content="Clecs" />
<meta property="al:android:package" content="com.stellarscepter.clecs" />
<meta property="al:android:class" content="com.stellarscepter.clecs.activity.LoginActivity" />
<meta property="al:web:should_fallback" content="false" />
<title>Stellarscepter</title>
</head>
<body>
</body>
</html>
EDIT 1:
I tried with either test and real Facebook user, that has already received an invite and not received any one. I also tried with users that have autorized and not autorized via Facebook. In every combination no Facebook notification shown.
Found out that is a Facebook SDK bug reported here.
Related
Before starting, as is stated in the title, I'm learning .NET MAUI and I'm very new in this.
My problem is that I can't find a way to share information from a page to a previous page.
What I'm trying to do is the following:
In the MainPage, have a button that once pressed, sends the user to another page, let's call it LoginPage, there, ask the user for his name, and after the input, redirect him to the previous page showing an "Hello {Name}, and welcome!"
MainPage code:
string Name = "";
string greetings = "";
async private void LogintBtn_Clicked(object sender, EventArgs e)
{
{
await Navigation.PushAsync(new LoginPage());
}
greetings = $"Welcome {Name}!";
Greetinglbl.Text = greetings;
}
Log in code:
public string name { get; set; }
private void btnRegister_Clicked(object sender, EventArgs e)
{
if (ValidateName()==false) { return; };
Navigation.PopAsync();
}
private bool ValidateName()
{
if (string.IsNullOrWhiteSpace(txtRegistro.Text))
{
return false;
}
else
return true;
}
Beside this, I don't know how to share information between these pages.
I have seen that a lot of devs use MVVM but I can't get a Beginners guide propperly, even watching the .NET MAUI Beginners Guides from James Montemagno doesn't help me.
I've also tried using something like
await Shell.Current.GoToAsync($"LoginPage?Name={Name}");
that, for what I read is used to send data but don't know where to put it, plus triying to navigate with the same line throws an error (null).
Plus, most of the videos only shows how to send Data to the next Page, not the previous, and usually to a collection, and some of them import NuGet Packages that I don't see to be necessary in this project.
In your scenario, you could share the data through Constructor, here's the code snippet below for your reference.
MainPage:
Xaml:
<ScrollView>
<VerticalStackLayout
Spacing="25"
Padding="30,0"
VerticalOptions="Center">
<Label Text="MainPage"></Label>
<Button
Text="To Login Page"
Clicked="OnClicked"
HorizontalOptions="Center" />
</VerticalStackLayout>
</ScrollView>
Code-behind:
public MainPage()
{
InitializeComponent();
}
public MainPage(string a)
{
InitializeComponent();
App.Current.MainPage.DisplayAlert("Welcome Back",a,"OK");
}
private async void OnClicked(object sender, EventArgs e)
{
await Navigation.PushAsync(new LoginPage());
}
LoginPage:
Xaml:
<VerticalStackLayout>
<Label Text="LoginPage"></Label>
<Entry x:Name="myentry"/>
<Button
Text="ToMain"
Clicked="BackTo"
HorizontalOptions="Center" />
</VerticalStackLayout>
Code-behind:
public LoginPage()
{
InitializeComponent();
}
private async void BackTo(object sender, EventArgs e)
{
await Navigation.PushModalAsync(new MainPage(myentry.Text));
}
Last but not least, in your App.xaml.cs, use it like below:
MainPage = new NaviagtionPage(new MainPage())
I'm using simple code of modified Captive portal with asynchronous web portal (from ESPAsyncWebServer library - https://github.com/me-no-dev/ESPAsyncWebServer). It send html page from SPIFFS flash memory.
The way it is working now, is that it send index.html on any connection. I've just modified single line that in mentioned example was sending hmtl code. What I'd like to archive, is to be able to send more files, like html file and image.
So here is my code:
#include <DNSServer.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include "ESPAsyncWebServer.h"
#include <SPIFFS.h>
DNSServer dnsServer;
AsyncWebServer server(80);
class CaptiveRequestHandler : public AsyncWebHandler {
public:
CaptiveRequestHandler() {}
virtual ~CaptiveRequestHandler() {}
bool canHandle(AsyncWebServerRequest *request) {
//request->addInterestingHeader("ANY");
return true;
}
void handleRequest(AsyncWebServerRequest *request) {
request->send(SPIFFS, "/index.html", String(), false);
}
};
void setup() {
Serial.begin(115200);
if (!SPIFFS.begin()) {
Serial.println("An Error has occurred while mounting SPIFFS");
return;
}
WiFi.softAP("esp-captive");
dnsServer.start(53, "*", WiFi.softAPIP());
server.addHandler(new CaptiveRequestHandler()).setFilter(ON_AP_FILTER);//only when requested from AP
server.on("/image1", HTTP_GET, [](AsyncWebServerRequest * request) {
request->send(SPIFFS, "/image1.jpg", "image/jpg"); // this part has been modified
});
server.begin();
}
void loop() {
dnsServer.processNextRequest();
}
I've tried to add
server.on("/image1", HTTP_GET, [](AsyncWebServerRequest * request) {
request->send(SPIFFS, "/image1.jpg", "image/jpg"); // this part has been modified
});
in setup section as explained here - https://randomnerdtutorials.com/display-images-esp32-esp8266-web-server/
But it's not working. I've tried messing with path changing "/" in places whare it appears, but with no luck. Further, if I change
void handleRequest(AsyncWebServerRequest *request) {
request->send(SPIFFS, "/index.html", String(), false);
}
to
void handleRequest(AsyncWebServerRequest *request) {
request->send(SPIFFS, "/image1.jpg", "image/jpg");
}
when logging to AP I get image not website, so I think paths are good.
To add more information this is my webpage code:
<!DOCTYPE html>
<html style="height: 100%">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body style="background-image: url('image1'); background-size: contain; background-color: black; background-repeat: no-repeat; background-position: 50% 0%; height=100%">
<h1 style="color:white">ESP32</h1>
</body>
</html>
and it is working fine on non-captive_portal solution (as explaind in previously mentioned tutorial).
So my question is how can I get to load not only single file on captive portal in asynchronous webserver, but more complicated (still very simple) webpage?
I struggeled with it for a while. But here is the answer. On the CaptiveRequestHandler() {} you can place your http calls.
Here is an example for you:
class CaptiveRequestHandler : public AsyncWebHandler {
public:
CaptiveRequestHandler() {
/* THIS IS WHERE YOU CAN PLACE THE CALLS */
server.onNotFound([](AsyncWebServerRequest *request){
AsyncWebServerResponse* response = request->beginResponse(SPIFFS, "/NotFound.html", "text/html");
request->send(response);
});
server.on("/Bootstrap.min.css", HTTP_GET, [](AsyncWebServerRequest *request) {
AsyncWebServerResponse* response = request->beginResponse(SPIFFS, "/Bootstrap.min.css", "text/css");
request->send(response);
});
}
virtual ~CaptiveRequestHandler() {}
bool canHandle(AsyncWebServerRequest *request) {
//request->addInterestingHeader("ANY");
return true;
}
void handleRequest(AsyncWebServerRequest *request) {
request->send(SPIFFS, "/index.html", String(), false);
}
};
Use Case:
I have a asp.net core web application with signalR core for messaging. :)
Problem:
I have to receive messages from a socket connection [via System.Net.Sockets] (machine with own socket communication)
Is there any way to integrate the socket client in the web app (maybe Progamm.cs or Startup.cs?)
And how can I get access to the signalR to forward the received message to the signalR Hub?
thx
I suggest you to read the stockticker sample on : https://learn.microsoft.com/en-us/aspnet/signalr/overview/getting-started/tutorial-server-broadcast-with-signalr
I show you here a small sample which you can adapt to your application. You have to subscribe the messages from your own socket communication and then you can forward this messages to the connected clients.
Here is a small sample how to send the time from server to the clients.
(The interesting part for you is the line GlobalHost.ConnectionManager.GetHubContext<ClockHub>().Clients.All.sendTime(DateTime.UtcNow.ToString());. Which this you can send something to all connected clients.
My main class is a clock which sends the actual time to all connected clients:
public class Clock
{
private static Clock _instance;
private Timer timer;
private Clock()
{
timer = new Timer(200);
timer.Elapsed += Timer_Elapsed;
timer.Start();
}
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{ // ---> This is the important part for you: Get hubContext where ever you use it and call method on hub GlobalHost.ConnectionManager.GetHubContext<ClockHub>().Clients.All.sendTime(DateTime.UtcNow.ToString());
GlobalHost.ConnectionManager.GetHubContext<ClockHub>().Clients.Clients()
}
public static Clock Instance
{
get
{
if (_instance == null)
{
_instance = new Clock();
}
return _instance;
}
}
}
}
In the startup I created a sigleton instance of this clock, which lives as long as the application is running.
public class Startup
{
public void Configuration(IAppBuilder app)
{
var inst = Clock.Instance;
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR();
}
}
}
My Hub:
public class ClockHub : Hub<IClockHub>
{
}
Hub interface which defines the method, which the server can call:
public interface IClockHub
{
void sendTime(string actualTime);
}
This is the clients part:
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8" />
</head>
<body>
<div id="timeLabel" ></div>
<script src="scripts/jquery-1.6.4.min.js"></script>
<script src="scripts/jquery.signalR-2.2.0.js"></script>
<script src="signalr/hubs"></script>
<script>
$(function () { // I use jQuery in this example
var ticker = $.connection.clockHub;
function init() {
}
ticker.client.sendTime = function (h) {
$("#timeLabel").html(h);
}
$.connection.hub.start().done(init);
});
</script>
</body>
</html>
How to inject hubcontext in asp.net core 2.x
Call SignalR Core Hub method from Controller
Vertx3.0 http simpleform file uploader is throwing error for multiple file.
Am using vertx3.0 simple form upload. It is working fine when i upload single file. If the form has the input "multiple" and choose multiple files, The HTTPServerUpload is throwing error "Response has already been written". Since the response is end in the endhandler for 1st file, it is throwing this error for subsequent files. is there any other way for multiple files ?
Simpleform file upload using vertx3.0
public class SimpleFormUploadServer extends AbstractVerticle {
public static void main(String[] args) {
Runner.runExample(SimpleFormUploadServer.class);
}
#Override
public void start() throws Exception {
vertx.createHttpServer()
.requestHandler(req -> {
if (req.uri().equals("/")) {
// Serve the index page
req.response().sendFile("index.html");
} else if (req.uri().startsWith("/form")) {
req.setExpectMultipart(true);
req.uploadHandler(upload -> {
upload.exceptionHandler(cause -> {
req.response().setChunked(true)
.end("Upload failed");
});
upload.endHandler(v -> {
req.response()
.setChunked(true)
.end("Successfully uploaded to "
+ upload.filename());
});
// FIXME - Potential security exploit! In a real
// system you must check this filename
// to make sure you're not saving to a place where
// you don't want!
// Or better still, just use Vert.x-Web which
// controls the upload area.
upload.streamToFileSystem(upload.filename());
});
} else {
req.response().setStatusCode(404);
req.response().end();
}
}).listen(8080);
}
}
Exception :
SEVERE: Unhandled exception
java.lang.IllegalStateException: Response has already been written
at io.vertx.core.http.impl.HttpServerResponseImpl.checkWritten(HttpServerResponseImpl.java:561)
at io.vertx.core.http.impl.HttpServerResponseImpl.end0(HttpServerResponseImpl.java:389)
at io.vertx.core.http.impl.HttpServerResponseImpl.end(HttpServerResponseImpl.java:307)
at io.vertx.core.http.impl.HttpServerResponseImpl.end(HttpServerResponseImpl.java:292)
at com.nokia.doas.vertx.http.upload.SimpleFormUploadServer$1$1$2.handle(SimpleFormUploadServer.java:85)
at com.nokia.doas.vertx.http.upload.SimpleFormUploadServer$1$1$2.handle(SimpleFormUploadServer.java:1)
at io.vertx.core.http.impl.HttpServerFileUploadImpl.notifyEndHandler(HttpServerFileUploadImpl.java:213)
at io.vertx.core.http.impl.HttpServerFileUploadImpl.lambda$handleComplete$165(HttpServerFileUploadImpl.java:206)
at io.vertx.core.file.impl.AsyncFileImpl.lambda$doClose$226(AsyncFileImpl.java:470)
at io.vertx.core.impl.ContextImpl.lambda$wrapTask$16(ContextImpl.java:335)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:358)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:357)
at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:112)
at java.lang.Thread.run(Unknown Source)
index.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title></title>
</head>
<body>
<form action="/form" ENCTYPE="multipart/form-data" method="POST" name="wibble">
choose a file to upload:<input type="file" name="files" multiple="multiple"/><br>
<input type="submit"/>
</form>
</body>
</html>
You can use vertx-web to easily handle file uploads:
router.route().handler(BodyHandler.create());
router.post("/some/path/uploads").handler(routingContext -> {
Set<FileUpload> uploads = routingContext.fileUploads();
// Do something with uploads....
});
Moreover, you will take benefits of the routing facility, and you can even serve static files such as index.html.
Hope this will help.
Multiple file upload is achievable in vert.x. Use multiple upload button in HTML and use uploadHandler of HttpRequest. UploadHandler would be invoked as many times any many files have been uploaded.
HttpServerRequest request = routingContext.request();
request.setExpectMultipart(true);
request.endHandler(new Handler<Void>() {
#Override
public void handle(Void aVoid) {
MultiMap entries = request.formAttributes();
Set<String> names = entries.names();
logger.info("UPLOAD_CONTENT: fileName = "+entries.get("fileName"));
logger.info("UPLOAD_CONTENT: type = "+entries.get("type"));
logger.info("UPLOAD_CONTENT: names = "+names);
request.response().setChunked(true).end(createResponse("SUCCESS"));
}
});
// This would be called multiple times
request.uploadHandler(upload -> {
upload.exceptionHandler(new Handler<Throwable>() {
#Override
public void handle(Throwable error) {
logger.error("UPLOAD_CONTENT: Error while uploading content "+upload.filename());
logger.error("UPLOAD_CONTENT: error = "+error.toString());
error.printStackTrace();
request.response().setChunked(true).end(createResponse("FAILURE"));
}
});
upload.endHandler(new Handler<Void>() {
#Override
public void handle(Void aVoid) {
logger.info("UPLOAD_CONTENT: fileName = "+upload.filename());
logger.info("UPLOAD_CONTENT: name = "+upload.name());
logger.info("UPLOAD_CONTENT: contentType = "+upload.contentType());
logger.info("UPLOAD_CONTENT: size = "+upload.size());
UtilityFunctions.uploadToS3(upload.filename(), "testfolder");
}
});
upload.streamToFileSystem(upload.filename());
});
I am creating an app on Facebook and am trying to figure out what the proper way to authenticate and log into the app is. I don't want it to be accessible when they log out of Facebook and currently using OAuth 2.0 the app still totally functions by going to apps.facebook.com/myappname, even though the top bar to log into Facebook is there.
Here is my onModuleLoad :
public void onModuleLoad() {
AuthRequest req = new AuthRequest(FACEBOOK_AUTH_URL, FACEBOOK_CLIENT_ID);
AUTH.login(req, new Callback<String, Throwable>() {
#Override
public void onSuccess(String token) {
f_token = token;
startAppAfterLogin();
}
#Override public void onFailure(Throwable caught) {
Window.Location.assign("https://www.facebook.com/login.php");
}
});
}
Obviously the startAppAfterLogin() is still being called when they have logged out, anyone have any ideas what to do?