Working with Pusher, issues with invalid signature following error:
Invalid signature: Expected HMAC SHA256 hex digest of socketID:channel, but got hash.
Here is my code:
public static PusherOptions pusherChannelAuthorise(){
Log.v(TAG, "pusherChannelAuthorise");
mMobileToken = Handler_Login.fetchmobile();
PUSHER_MOBILETOKEN_MAP.put(PUSHER_MOBILETOKEN_LABEL, mMobileToken);
HttpAuthorizer authoriser = new HttpAuthorizer(url);
authoriser.setHeaders(PUSHER_MOBILETOKEN_MAP);
options = new PusherOptions().setAuthorizer(authoriser);
return options;
}
public static void connect(){
Log.v(TAG, "connect" + "::CONNECTED::");
PusherOptions presenceChannelOptions = pusherChannelAuthorise();
presenceChannelConnected = true;
pusher = new Pusher(pusherHash, presenceChannelOptions);
pusher.connect(new ConnectionEventListener() {
#Override
public void onConnectionStateChange(ConnectionStateChange change) {
socketId = pusher.getConnection().getSocketId();
Log.v(TAG, "The socketId is: " + socketId);
}
#Override
public void onError(String message, String code, Exception e) {
Log.v(TAG, "There was a problem connecting!");
}
}, ConnectionState.CONNECTED);
presencechannel = pusher.subscribePresence(PUSHER_PUBLIC_CHANNEL_NAME, listener);
String myUuid = Handler_Login.getMyUuid();
privatechannel = pusher.subscribePrivate(DOCSYNC_CHANNEL + myUuid, docSyncListener);
privatechannel.bind("client-init", docSyncListener = new PrivateChannelEventListener() {
#Override
public void onEvent(String channelName, String eventName, String data) {
Log.v(TAG, "Private Test onEvent: " + channelName + " " + eventName + " " + data);
}
#Override
public void onSubscriptionSucceeded(String channelName) {
Log.v(TAG, "Private Channel onSubscriptionSucceeded: " + channelName);
}
#Override
public void onAuthenticationFailure(String message, Exception e) {
Log.v(TAG, "Private Channel onAuthenticationFailure: " + message + ":::" + e);
}
});
}
What am I doing wrong? Do I have to set additional parameters in the headers for the authoriser? #leggetter
Authentication to the presence channel works fine, but the private one fails.
EDIT:
Server Code (PHP, Laravel):
public function postMobilePusher(Request $request)
{
if (null !== $request->header('mobileToken')) {
$currentUser = User::where('mobileToken', '=', $request->header('mobileToken'))->first();
if (null !== $currentUser) {
define('APP_ID', ID);
define('APP_KEY', KEY);
define('APP_SECRET', SECRET);
$pusher = new Pusher(APP_KEY, APP_SECRET, APP_ID);
$socket_id = $request->get('socket_id');
$channel_name = $request->get('channel_name');
$user_id = $currentUser->id;
$user_info = [
'firstName' => $currentUser->firstName
];
return $auth = $pusher->presence_auth( $channel_name, $socket_id, $user_id, $user_info );
}
}
return abort(403, 'Unauthorized action.');
}
Update the server-side code to use socket_auth for private channels and presence_auth for presence channels:
public function postMobilePusher(Request $request)
{
if (null !== $request->header('mobileToken')) {
$currentUser = User::where('mobileToken', '=', $request->header('mobileToken'))->first();
if (null !== $currentUser) {
define('APP_ID', ID);
define('APP_KEY', KEY);
define('APP_SECRET', SECRET);
$pusher = new Pusher(APP_KEY, APP_SECRET, APP_ID);
$socket_id = $request->get('socket_id');
$channel_name = $request->get('channel_name');
$auth = null;
if(starts_with($channel_name, 'private-')) {
// TODO: check user has permission to access channel
$auth = $pusher->socket_auth($channel_name, $socket_id);
}
else {
// presence
// TODO: check user has permission to access channel
$user_id = $currentUser->id;
$user_info = [
'firstName' => $currentUser->firstName
];
$auth = $pusher->presence_auth( $channel_name, $socket_id, $user_id, $user_info );
}
}
}
return abort(403, 'Unauthorized action.');
}
Related
I have an update profile API, where first name, last name are one of the parameters. I have separated the name into two strings with space as delimiter. But in case if the user doesn't give last name and update, the page crashes saying "ArrayIndex Out of Bounds Exception". I tried putting an if condition to pass last name value as "space" incase last name is empty. But it doesn't work. Please help to validate this condition and pass value accordingly. Attached the specific piece of code below:
Code
private void updateprofile() {
firstname = edtName.getText().toString();
lastname = edtName.getText().toString();
splitstring = txtName.split(" ");
firstname = splitstring[0].trim();
lastname = splitstring[1].trim();
if(TextUtils.isEmpty(lastname))
{
lastname=" ";
}
else
{
lastname = splitstring[1].trim();
}
Call<UpdateProfile> call = apiService.updateprofile(userId, firstname, lastname, profileurl, location, email, mobilenumber);
Log.e("DATA PASSED", userId + " " + firstname + " " + lastname + " " + profileurl + " " + location + email + mobilenumber);
call.enqueue(new Callback<UpdateProfile>() {
#Override
public void onResponse(Call<UpdateProfile> call, Response<UpdateProfile> response) {
if (response.isSuccessful()) {
String status = response.body().getStatus();
if (status.equalsIgnoreCase("1")) {
//Toast.makeText(getContext(), response.body().getMessage(), Toast.LENGTH_SHORT).show();
mainActivity.imgHomeMenu.setImageResource(R.drawable.edit_icon);
flagoption = true;
imgEditPhoto.setVisibility(View.GONE);
mainActivity.txvTitle.setText("PROFILE");
edtName.setEnabled(false);
edtLocation.setEnabled(false);
edtEmail.setEnabled(false);
edtPhone.setEnabled(false);
linearEmail.setBackground(getContext().getResources().getDrawable(R.drawable.button_background_profile_changes_two));
} else {
Toast.makeText(getContext(), response.body().getMessage(), Toast.LENGTH_SHORT).show();
}
}
}
#Override
public void onFailure(Call<UpdateProfile> call, Throwable t) {
}
});
}
Profile View:
private void callProfileApi(Context context) {
vehicleList = new ArrayList<>();
Call<ProfileDetails> call = apiService.callProfile(userId);
Log.e("USER ID INSIDE API", userId);
call.enqueue(new Callback<ProfileDetails>() {
#Override
public void onResponse(Call<ProfileDetails> call, Response<ProfileDetails> response) {
if (response.isSuccessful()) {
ProfileDetails resp = response.body();
if (resp != null) {
String status = resp.getStatus();
if (status.equalsIgnoreCase("1")) {
profileurl = resp.getUserDetail().getImage();
txtName = resp.getUserDetail().getName();
String joineddate = resp.getUserDetail().getJoined();
String[] join = joineddate.split(" ");
Log.e("join", join[0]);
splitstring = txtName.split(" ");
firstname = splitstring[0].trim();
lastname = splitstring[1].trim();
/*
if(edtName.getText().toString().trim().contains(" ")){
splitstring = txtName.split(" ");
firstname = splitstring[0].trim();
lastname = splitstring[1].trim();
}else{
lastname=" ";
Log.e("Name Error","Enter Name");
}*/
//txtjoinedDate = GlobalMethods.Date(join[0]);
txtjoinedDate = resp.getUserDetail().getJoined();
rating = resp.getUserDetail().getRating();
location = resp.getUserDetail().getLocation();
email = resp.getUserDetail().getEmail();
mobilenumber = resp.getUserDetail().getMobile();
ratingbar.setRating(Float.parseFloat(rating));
emailverification = resp.getUserDetail().getEmailVerification();
if (emailverification.equalsIgnoreCase("0")) {
txtEmail.setText("Verify");
txtEmail.setBackground(getResources().getDrawable(R.drawable.button_background_profile_changes_three));
} else {
txtEmail.setText("Verified");
txtEmail.setBackground(getResources().getDrawable(R.drawable.button_background_profile_changes_two));
}
mobileverfication = resp.getUserDetail().getMobileVerification();
if (mobileverfication.equalsIgnoreCase("0")) {
txtPhone.setText("Verify");
txtPhone.setBackground(getResources().getDrawable(R.drawable.button_background_profile_changes_three));
} else {
txtPhone.setText("Verified");
txtPhone.setBackground(getResources().getDrawable(R.drawable.button_background_profile_changes_two));
}
vehicleList = resp.getVehicles();
if (vehicleList.size() > 0) {
myVehicleAdapter = new MyVehicleProfileAdapter(getActivity(), vehicleList, "3");
recycleVehicleRegister.setAdapter(myVehicleAdapter);
recycleVehicleRegister.setLayoutManager(new GridLayoutManager(getActivity(), 1, LinearLayoutManager.HORIZONTAL, false));
} else {
recycleVehicleRegister.setVisibility(View.GONE);
txtNovehicles.setVisibility(View.VISIBLE);
vehiclelayout.setVisibility(View.GONE);
}
reviewList = resp.getReviews();
if (reviewList.size() > 0) {
profileReviewsAdapter = new ProfileReviewsAdapter(getContext(), reviewList);
recycleViewfeedback.setAdapter(profileReviewsAdapter);
recycleViewfeedback.setLayoutManager(new LinearLayoutManager(getContext()));
} else {
recycleViewfeedback.setVisibility(View.GONE);
txtNoreviews.setVisibility(View.VISIBLE);
morereviewslayout.setVisibility(View.GONE);
/*morereviewslayout.setVisibility(View.GONE);
recycleViewfeedback.setVisibility(View.GONE);
notfoundlayout.setVisibility(View.GONE);*/
}
if (TextUtils.isEmpty(profileurl)) {
userProfiPlaceholder.setImageDrawable(getContext().getResources().getDrawable(R.drawable.profile_placeholder));
Glide.with(getContext()).load(profileurl).into(userProfiPlaceholder);
edtName.setText(txtName);
Log.e("PROFILE NAME", txtName);
ratingbar.setRating(Float.parseFloat(rating));
txtRateText.setText(rating);
txtBalance.setText("$"+resp.getUserDetail().getReferralBalance());
edtLocation.setText(location);
edtEmail.setText(email);
edtPhone.setText(mobilenumber);
edtId.setText(idproof);
} else {
Glide.with(getContext()).load(profileurl).into(userProfiPlaceholder);
edtName.setText(txtName);
Log.e("PROFILE NAME", txtName);
txtJoinedDate.setText("Joined" + " " + txtjoinedDate);
ratingbar.setRating(Float.parseFloat(rating));
txtRateText.setText(rating);
txtBalance.setText("$"+resp.getUserDetail().getReferralBalance());
edtLocation.setText(location);
edtEmail.setText(email);
edtPhone.setText(mobilenumber);
edtId.setText(idproof);
}
if (TextUtils.isEmpty(mobilenumber)) {
edtPhone.setHint("Phone Number");
}
if (TextUtils.isEmpty(location)) {
edtLocation.setHint("Location");
}
if (TextUtils.isEmpty(idimage)) {
edtId.setHint("ID Verified (passport)");
}
}
}
}
}
#Override
public void onFailure(Call<ProfileDetails> call, Throwable t) {
}
});
}
In case your string won't be having lastname then this statement will cause error even before you can check for null.
lastname = splitstring[1].trim();
Try directly checking if size() of your array is larger than index you are accessing. If the size is larger then do your initializing for lastname.
Simply Use
if(textName.getText().toString().trim().contains(" ")){
splitstring = txtName.split(" ");
if (splitstring.length>1) {
firstname = splitstring[0].trim();
lastname = splitstring[1].trim();
}
}else{
Log.e("Name Error","Enter first and last Name")
}
I want to get message in my chat activity without press back button in Quickblox instance chat
userData = new QBUser();
userData.setEmail(uNameStr);
userData.setPassword(uPwdStr);
userData.setId(user.getId());
You have to set listeners after the privateChat.sendMessage(chatMessage); so when you get success in listeners call notifydatasetchange method of the adapter.
private void sendMessage() {
// privateChatManager = chatService.getPrivateChatManager();
Log.d("PRIVATE", ">>>>> " + privateChatManager);
Log.d("INST", ">>>>> " + QBChatService.getInstance());
Log.d("CHAT ", "" + chatService);
Log.d("PRI", ">>>>> " + QBChatService.getInstance().getPrivateChatManager());
//login to chat firstly
if (messageEdt.length() > 0) {
privateChatMessageListener = new QBMessageListener<QBPrivateChat>() {
#Override
public void processMessage(QBPrivateChat privateChat, final QBChatMessage chatMessage) {
Log.e("privateChat ", " " + privateChat);
Log.e("chatMessage", "" + chatMessage);
chatListAdapter.notifyDataSetChanged();
}
#Override
public void processError(QBPrivateChat privateChat, QBChatException error, QBChatMessage originMessage) {
Log.e("privateChat ", " " + privateChat);
Log.e("QBChatMessage", "" + originMessage);
Log.e("error", "" + error);
}
};
privateChatManagerListener = new QBPrivateChatManagerListener() {
#Override
public void chatCreated(final QBPrivateChat privateChat, final boolean createdLocally) {
if (!createdLocally) {
privateChat.addMessageListener(privateChatMessageListener);
}
}
};
ChattingFragment.chatService.getPrivateChatManager().addPrivateChatManagerListener(privateChatManagerListener);
try {
QBChatMessage chatMessage = new QBChatMessage();
chatMessage.setBody(messageEdt.getText().toString());
chatMessage.setProperty("save_to_history", "1"); // Save a message to history
chatMessage.setProperty("notification_type", "1");
chatMessage.setSenderId(Integer.parseInt(Util.ReadSharePrefrence(getApplicationContext(), Constant.SHRED_PR.KEY_QB_USERID)));
chatMessage.setRecipientId(opponentId);
chatMessage.setMarkable(true);
privateChatManager = QBChatService.getInstance().getPrivateChatManager();
QBPrivateChat privateChat = privateChatManager.getChat(opponentId);
if (privateChat == null) {
privateChat = privateChatManager.createChat(opponentId, privateChatMessageListener);
}
// send message
privateChat.sendMessage(chatMessage);
privateChat.addMessageSentListener(privateChatMessageSentListener);
privateChat.addMessageListener(privateChatMessageListener);
} catch (SmackException.NotConnectedException e) {
Toast.makeText(PrivateChat.this, "Exception " + e, Toast.LENGTH_SHORT).show();
}
}
}
private QBMessageSentListener<QBPrivateChat> privateChatMessageSentListener = new QBMessageSentListener<QBPrivateChat>() {
#Override
public void processMessageSent(QBPrivateChat qbChat, QBChatMessage qbChatMessage) {
Log.d("MEHUL", "M " + qbChat);
Log.d("MSG", "MSG " + qbChatMessage);
hashmap = new HashMap<String, String>();
hashmap.put("id", "" + qbChatMessage.getId());
if (qbChatMessage.getBody() != null) {
hashmap.put("msg", "" + qbChatMessage.getBody());
} else {
hashmap.put("msg", "");
}
hashmap.put("recipient_id", "" + opponentId);
hashmap.put("sender_id", "" + user_id);
Collection<QBAttachment> collection = qbChatMessage.getAttachments();
if (collection != null && collection.size() > 0) {
for (QBAttachment attachment : collection) {
String imageid = attachment.getId();
String RecivedUrl = attachment.getUrl();
hashmap.put("url", "" + RecivedUrl);
}
//Here is the AsyncTask where I am trying to download image
//
}
String currentDateTimeString = DateFormat.getDateTimeInstance().format(new Date());
// textView is the TextView view that should display it
hashmap.put("updated_at", "" + currentDateTimeString);
chatArraylist.add(hashmap);
Toast.makeText(getApplicationContext(), "Message Sent Successfully", Toast.LENGTH_SHORT).show();
messageEdt.setText("");
chatListAdapter = new PrivateChatMsgListAdapter(getApplicationContext(), chatArraylist);
lvChatDetails.setAdapter(chatListAdapter);
lvChatDetails.setTranscriptMode(ListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
lvChatDetails.setStackFromBottom(true);
chatListAdapter.notifyDataSetChanged();
scrollMyListViewToBottom();
}
#Override
public void processMessageFailed(QBPrivateChat qbChat, QBChatMessage qbChatMessage) {
Log.d("MEHUL", "M " + qbChat);
Log.d("MSG", "ERR " + qbChatMessage);
}
};
I know this kind of questions are maybe too old, but I got stock with this silly thing.
I have an AsyncTask class which is a subclass of an activity class, and right now I want to call it from another class: following codes shows what I mean:
public class STA extends Activity {
public class ListSpdFiles extends AsyncTask<Void, Void, String[]> {
private static final String TAG = "ListSpdFiles: ";
/**
* Status code returned by the SPD on operation success.
*/
private static final int SUCCESS = 4;
private String initiator;
private String path;
private SecureApp pcas;
private boolean isConnected = false; // connected to PCAS service?
private PcasConnection pcasConnection = new PcasConnection() {
#Override
public void onPcasServiceConnected() {
Log.d(TAG, "pcasServiceConnected");
latch.countDown();
}
#Override
public void onPcasServiceDisconnected() {
Log.d(TAG, "pcasServiceDisconnected");
}
};
private CountDownLatch latch = new CountDownLatch(1);
public ListSpdFiles(String initiator, String path) {
this.initiator = initiator;
this.path = path;
}
private void init() {
Log.d(TAG, "starting task");
pcas = new AndroidNode(getApplicationContext(), pcasConnection);
isConnected = pcas.connect();
}
private void term() {
Log.d(TAG, "terminating task");
if (pcas != null) {
pcas.disconnect();
pcas = null;
isConnected = false;
}
}
#Override
protected void onPreExecute() {
super.onPreExecute();
init();
}
#Override
protected String[] doInBackground(Void... params) {
// check if connected to PCAS Service
if (!isConnected) {
Log.v(TAG, "not connected, terminating task");
return null;
}
// wait until connection with SPD is up
try {
if (!latch.await(20, TimeUnit.SECONDS)) {
Log.v(TAG, "unable to connected within allotted time, terminating task");
return null;
}
} catch (InterruptedException e) {
Log.v(TAG, "interrupted while waiting for connection in lsdir task");
return null;
}
// perform operation (this is where the actual operation is called)
try {
return lsdir();
} catch (DeadServiceException e) {
Log.i(TAG, "service boom", e);
return null;
} catch (DeadDeviceException e) {
Log.i(TAG, "device boom", e);
return null;
}
}
#Override
protected void onPostExecute(String[] listOfFiles) {
super.onPostExecute(listOfFiles);
if (listOfFiles == null) {
Log.i(TAG, "task concluded with null list of files");
// tv.setText("task concluded with a null list of files");
} else {
Log.i(TAG, "task concluded with the following list of files: "
+ Arrays.toString(listOfFiles));
//tv.setText("List of files received is:\n" + Arrays.toString(listOfFiles));
}
term();
}
#Override
protected void onCancelled(String[] listOfFiles) {
super.onCancelled(listOfFiles);
Log.i(TAG, "lsdir was canceled");
term();
}
/**
* Returns an array of strings containing the files available at the given path, or
* {#code null} on failure.
*/
private String[] lsdir() throws DeadDeviceException, DeadServiceException {
Result<List<String>> result = pcas.lsdir(initiator, path); // the lsdir call to the
final Global globalVariable = (Global) getApplicationContext();
if (globalVariable.getPasswordButt() == false) {
// Calling Application class (see application tag in AndroidManifest.xml)
// Get name and email from global/application context
final boolean isusername = globalVariable.getIsUsername();
if (isusername == true) {
String username = "/" + getLastAccessedBrowserPage() + ".username" + ".txt";
//String password = "/" + CurrentURL + "password" + ".txt";
ByteArrayOutputStream baos = new ByteArrayOutputStream();
pcas.readFile(initiator, username, baos);
Log.i(TAG, "OutputStreampassword: "
+ new String(baos.toByteArray()));
String name = new String(baos.toByteArray());
if (!name.equalsIgnoreCase("")) {
globalVariable.setUsername(name);
// getCurrentInputConnection().setComposingText(name, 1);
// updateCandidates();
}
globalVariable.setIsUsername(false);
} else if (isusername == false)
Log.i(TAG, "Wrong Input Type For Username.");
// globalVariable.setUsernameButt(false);
} else if (globalVariable.getPasswordButt() == true) {
// Calling Application class (see application tag in AndroidManifest.xml)
// final Global globalVariable = (Global) getApplicationContext();
// Get name and email from global/application context
final boolean ispassword = globalVariable.getIsPassword();
if (ispassword == true) {
// String username = "/" + CurrentURL + "username" + ".txt";
String password = "/" + getLastAccessedBrowserPage() + ".password" + ".txt";
ByteArrayOutputStream baos = new ByteArrayOutputStream();
pcas.readFile(initiator, password, baos);
Log.i(TAG, "OutputStreampassword: "
+ new String(baos.toByteArray()));
String name = new String(baos.toByteArray());
if (!name.equalsIgnoreCase("")) {
globalVariable.setPassword(name);
//getCurrentInputConnection().setComposingText(name, 1);
// updateCandidates();
}
globalVariable.setIsPassword(false);
} else if (ispassword == false)
Log.i(TAG, "Wrong Input Type For Password.");
globalVariable.setPasswordButt(false);
// boolpassword=false;
}
//}
if (result.getState() != SUCCESS) {
Log.v(TAG, "operation failed");
return null;
}
if (result.getValue() == null) {
Log.v(TAG, "operation succeeded but operation returned null list");
return null;
}
return result.getValue().toArray(new String[0]);
}
}
public String getLastAccessedBrowserPage() {
String Domain = null;
Cursor webLinksCursor = getContentResolver().query(Browser.BOOKMARKS_URI, Browser.HISTORY_PROJECTION, null, null, Browser.BookmarkColumns.DATE + " DESC");
int row_count = webLinksCursor.getCount();
int title_column_index = webLinksCursor.getColumnIndexOrThrow(Browser.BookmarkColumns.TITLE);
int url_column_index = webLinksCursor.getColumnIndexOrThrow(Browser.BookmarkColumns.URL);
if ((title_column_index > -1) && (url_column_index > -1) && (row_count > 0)) {
webLinksCursor.moveToFirst();
while (webLinksCursor.isAfterLast() == false) {
if (webLinksCursor.getInt(Browser.HISTORY_PROJECTION_BOOKMARK_INDEX) != 1) {
if (!webLinksCursor.isNull(url_column_index)) {
Log.i("History", "Last page browsed " + webLinksCursor.getString(url_column_index));
try {
Domain = getDomainName(webLinksCursor.getString(url_column_index));
Log.i("Domain", "Last page browsed " + Domain);
return Domain;
} catch (URISyntaxException e) {
e.printStackTrace();
}
break;
}
}
webLinksCursor.moveToNext();
}
}
webLinksCursor.close();
return null;
}
public String getDomainName(String url) throws URISyntaxException {
URI uri = new URI(url);
String domain = uri.getHost();
return domain.startsWith("www.") ? domain.substring(4) : domain;
}}
Would you please tell me what should I do to fix this code?
Looking over the code I did not see anywhere you referenced anything from the Activity itself besides the application context so you can move the ListSpdFiles class to its own java file and pass it a context into the constructor when you make a new instance of it.
Put this class in a ListSpdFiles.java file so it is no longer an inner class.
public class ListSpdFiles extends AsyncTask<Void, Void, String[]> {
Context applicationContext;
public ListSpdFiles(Context context, String initiator, String path) {
this.initiator = initiator;
this.path = path;
applicationContext = context.getApplicationContext();
}
// The rest of your code still goes here. Replace other calls to
// getApplicationContext() with the new applicationContext field
}
You can now use this class anywhere a Context is available. You create a new instance by doing:
ListSpdFiles listSpdFilesTask = new ListSpdFiles(context, "someInitiator", "somePath");
listSpdFilesTask.execute();
I am working on an app in Unity3D which can upload tracks to SoundCloud. I have been working on this for a while but i can't get it to work. I am using HttpWebRequest for the request to SoundCloud and this works fine on Unity for Windows. But when i try it on my Android device i get the following message: 'Request entity contains invalid byte sequence. Please transmit valid UTF-8.'.
Below is the part of code that i use (got it from somewhere on the internet).
I made sure i was uploading the same file on Windows as on Android and did the request to RequestBin. Now, when i compared the two, i noticed that the raw data is almost completely identical except for the end:
Ending Windows: ÿàþ³þDþÿýëýÅýÙý
Ending Android: ÿàþ³þDþÿýëýÅýÙý[FF]þÞýþûýCþxþZþ{þ
So as you can see, on Android there is more data. Can someone explain to me what is going on here?
I started with posts on the Unity community, now trying it here. Here you can find my question on the unity website for more information.
public class SoundCloudScript {
//Enter app credentials from here http://soundcloud.com/you/apps
private const string _clientId = "xxx";
private const string _clientSecret = "xxx";
//enter username and password a soundcloud user, e.g. your own credentials
private const string _username = "xxx";
private const string _password = "xxx";
private string soundCloudToken;
//private WebClient _webclient = new WebClient();
public string Status { get; set; }
public IEnumerator GetTokenAndUploadFile(MonoBehaviour mono, FileInfo file)
{
Debug.Log ( "GetTokenAndUploadFile() started");
ServicePointManager.ServerCertificateValidationCallback = (p1, p2, p3, p4) => true;
var form = new WWWForm ();
form.AddField ("client_id", _clientId);
form.AddField ("client_secret", _clientSecret);
form.AddField ("grant_type", "password");
form.AddField ("username", _username);
form.AddField ("password", _password);
//Authentication
string soundCloudTokenRes = "https://api.soundcloud.com/oauth2/token";
Debug.Log ( "Try to get token");
WWW download = new WWW(soundCloudTokenRes, form);
yield return download;
if(!string.IsNullOrEmpty(download.error))
{
Debug.Log ( "Error downloading: " + download.error );
}
else
{
var tokenInfo = download.text;
tokenInfo = tokenInfo.Remove(0, tokenInfo.IndexOf("token\":\"") + 8);
soundCloudToken = tokenInfo.Remove(tokenInfo.IndexOf("\""));
Debug.Log(string.Format("Token set: {0}", soundCloudToken));
UploadFile(file);
}
}
public void UploadFile(FileInfo file)
{
Debug.Log ("Start uploading!");
ServicePointManager.Expect100Continue = false;
var request = WebRequest.Create("https://api.soundcloud.com/tracks/") as HttpWebRequest;
//some default headers
request.Accept = "*/*";
request.Headers.Add("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.3");
request.Headers.Add("Accept-Encoding", "gzip,deflate,sdch");
request.Headers.Add("Accept-Language", "en-US,en;q=0.8,ru;q=0.6");
//file array
var files = new UploadFile[]
{
new UploadFile(file.FullName, "track[asset_data]", "application/octet-stream")
};
//other form data
var form = new System.Collections.Specialized.NameValueCollection();
form.Add("track[title]", "Some title");
form.Add("track[sharing]", "private");
form.Add("oauth_token", soundCloudToken);
form.Add("format", "json");
try
{
using (var response = HttpUploadHelper.Upload(request, files, form))
{
using (var reader = new StreamReader(response.GetResponseStream()))
{
reader.ReadToEnd();
}
}
Debug.Log ("Upload success!");
}
catch (WebException wex) {
if (wex.Response != null) {
using (var errorResponse = (HttpWebResponse)wex.Response) {
using (var reader = new StreamReader(errorResponse.GetResponseStream())) {
string error = reader.ReadToEnd();
Debug.Log ("Error(1/2): Message: " + wex.Message);
Debug.Log ("Error(2/2): " + error);
//TODO: use JSON.net to parse this string and look at the error message
}
}
}
}
//return "Nothing...";
}
}
public class StreamMimePart : MimePart
{
Stream _data;
public void SetStream(Stream stream)
{
_data = stream;
}
public override Stream Data
{
get
{
return _data;
}
}
}
public abstract class MimePart
{
NameValueCollection _headers = new NameValueCollection();
byte[] _header;
public NameValueCollection Headers
{
get { return _headers; }
}
public byte[] Header
{
get { return _header; }
}
public long GenerateHeaderFooterData(string boundary)
{
StringBuilder sb = new StringBuilder();
sb.Append("--");
sb.Append(boundary);
sb.AppendLine();
foreach (string key in _headers.AllKeys)
{
sb.Append(key);
sb.Append(": ");
sb.AppendLine(_headers[key]);
}
sb.AppendLine();
_header = Encoding.UTF8.GetBytes(sb.ToString());
return _header.Length + Data.Length + 2;
}
public abstract Stream Data { get; }
}
public class StringMimePart : MimePart
{
Stream _data;
public string StringData
{
set
{
_data = new MemoryStream(Encoding.UTF8.GetBytes(value));
}
}
public override Stream Data
{
get
{
return _data;
}
}
}
public class HttpUploadHelper
{
private HttpUploadHelper()
{ }
public static string Upload(string url, UploadFile[] files, NameValueCollection form)
{
HttpWebResponse resp = Upload((HttpWebRequest)WebRequest.Create(url), files, form);
using (Stream s = resp.GetResponseStream())
using (StreamReader sr = new StreamReader(s))
{
return sr.ReadToEnd();
}
}
public static HttpWebResponse Upload(HttpWebRequest req, UploadFile[] files, NameValueCollection form)
{
List<MimePart> mimeParts = new List<MimePart>();
try
{
foreach (string key in form.AllKeys)
{
StringMimePart part = new StringMimePart();
part.Headers["Content-Disposition"] = "form-data; name=\"" + key + "\"";
part.StringData = form[key];
mimeParts.Add(part);
}
int nameIndex = 0;
foreach (UploadFile file in files)
{
StreamMimePart part = new StreamMimePart();
if (string.IsNullOrEmpty(file.FieldName))
file.FieldName = "file" + nameIndex++;
part.Headers["Content-Disposition"] = "form-data; name=\"" + file.FieldName + "\"; filename=\"" + file.FileName + "\"";
part.Headers["Content-Type"] = file.ContentType;
part.SetStream(file.Data);
mimeParts.Add(part);
}
string boundary = "----------" + DateTime.Now.Ticks.ToString("x");
req.ContentType = "multipart/form-data; boundary=" + boundary;
req.Method = "POST";
long contentLength = 0;
byte[] _footer = Encoding.UTF8.GetBytes("--" + boundary + "--\r\n");
foreach (MimePart part in mimeParts)
{
contentLength += part.GenerateHeaderFooterData(boundary);
}
req.ContentLength = contentLength + _footer.Length;
Debug.Log ("ContentLength: " + req.ContentLength);
byte[] buffer = new byte[8192];
byte[] afterFile = Encoding.UTF8.GetBytes("\r\n");
int read;
foreach(var header in req.Headers)
{
Debug.Log(header);
}
using (Stream s = req.GetRequestStream())
{
foreach (MimePart part in mimeParts)
{
s.Write(part.Header, 0, part.Header.Length);
while ((read = part.Data.Read(buffer, 0, buffer.Length)) > 0)
{
s.Write(buffer, 0, read);
Debug.Log ("Buffer: >>" + System.Text.Encoding.UTF8.GetString(buffer) + "<<");
}
//Debug.Log ("Buffer: " + System.Text.Encoding.UTF8.GetString(buffer));
part.Data.Dispose();
s.Write(afterFile, 0, afterFile.Length);
Debug.Log ("Buffer-End: >>" + System.Text.Encoding.UTF8.GetString(afterFile) + "<<");
}
s.Write(_footer, 0, _footer.Length);
Debug.Log ("Footer: >>" + System.Text.Encoding.UTF8.GetString(_footer) + "<<");
}
return (HttpWebResponse)req.GetResponse();
}
catch (Exception e)
{
Debug.Log ("Crash! Message: " + e.Message);
foreach (MimePart part in mimeParts)
if (part.Data != null)
part.Data.Dispose();
throw;
}
}
}
public class UploadFile
{
Stream _data;
string _fieldName;
string _fileName;
string _contentType;
public UploadFile(Stream data, string fieldName, string fileName, string contentType)
{
_data = data;
_fieldName = fieldName;
_fileName = fileName;
_contentType = contentType;
}
public UploadFile(string fileName, string fieldName, string contentType)
: this(File.OpenRead(fileName), fieldName, Path.GetFileName(fileName), contentType)
{ }
public UploadFile(string fileName)
: this(fileName, null, "application/octet-stream")
{ }
public Stream Data
{
get { return _data; }
set { _data = value; }
}
public string FieldName
{
get { return _fieldName; }
set { _fieldName = value; }
}
public string FileName
{
get { return _fileName; }
set { _fileName = value; }
}
public string ContentType
{
get { return _contentType; }
set { _contentType = value; }
}
}
It's working!! The problem was that at some point i used StringBuilder.AppendLine() to add a new line. This works fine on Windows, but on Android it didn't work... (i figured it out because the Content-Length was not the same for Windows and Android.)
I fixed it by instead of using 'StringBuilding.AppendLine()', i use 'StringBuilder.Append("\r\n")'
so here is my code for connecting and getting the values:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Facebook;
using SmartLocalization;
public class mainMenuFacebook : MonoBehaviour {
public string FBname;
public string FBsurname;
Dictionary<string, string> profile = new Dictionary<string, string>();
// Use this for initialization
void OnMouseDown()
{
FB.Login("publish_actions,public_profile", LoginCallback); // logine tıklama
}
void Awake() {
FB.Init(SetInit, OnHideUnity); //facebook başlangıcı
}
private void SetInit()
{
if (FB.IsLoggedIn)
{
// Util.Log("Already logged in");
OnLoggedIn();
}
}
private void OnHideUnity(bool isGameShown)
{
if (!isGameShown)
{
// pause the game - we will need to hide
Time.timeScale = 0;
}
else
{
// start the game back up - we're getting focus again
Time.timeScale = 1;
}
}
void LoginCallback(FBResult result)
{
Util.Log("LoginCallback");
if (FB.IsLoggedIn)
{ gameObject.guiTexture.enabled = false;
OnLoggedIn();
}
}
void OnLoggedIn()
{
FB.API("/me?fields=first_name,last_name,email", Facebook.HttpMethod.GET, APICallback); // adını ve idyi çekiyoruz.
}
void APICallback(FBResult result)
{
if (result.Error != null)
{
// Let's just try again
// FB.API("/me?fields=id,first_name,last_name,email,friends.limit(100).fields(first_name,last_name,id)", Facebook.HttpMethod.GET, APICallback);
return;
}
Debug.Log(result.Text);
profile = Util.DeserializeJSONProfile(result.Text);
FBname = profile["first_name"];
FBsurname = profile["last_name"]; // **IT GIVES ERROR**
Debug.Log(FBsurname + " " + FBname);
//PlayerPrefs.SetString("surname",profile["last_name"]);
//PlayerPrefs.SetString("email",profile["email"]);
gameObject.guiTexture.enabled = false;
GameObject.Find("Wellcome").guiText.enabled = true;
GameObject.Find("Wellcome").guiText.text = LanguageManager.Instance.GetTextValue("menu.hosgeldin") + " <b><color=#ffa500ff>" + FBname + "</color></b>, <i>" + LanguageManager.Instance.GetTextValue("menu.cikis") +"</i>";
PlayerPrefs.SetString("name",FBname);
}
}
when i only try to get first_name everything is okay. But i need to get last_name and email too. I think i cant serialize because when i try to Debug.Log(profile.Count); it shows 1.
How can i fix it?
Given error is:
KeyNotFoundException: The given key was not present in the dictionary.
System.Collections.Generic.Dictionary`2[System.String,System.String].get_Item (System.String key) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Collections.Generic/Dictionary.cs:150)
mainMenuFacebook.APICallback (.FBResult result) (at Assets/Scripts/mainMenuFacebook.cs:84)
Facebook.AsyncRequestString+<Start>c__Iterator0.MoveNext ()
Try this:
public void OnMouseDown()
{
List<string> permissions = new List<string>() { "public_profile", "email" };
FB.LogInWithReadPermissions(permissions,AuthCallback);
Debug.Log("Facebook Login");
}
In AuthCallback: if user logs in successfully, get info from FB api.
private void AuthCallback(ILoginResult result)
{
if(FB.IsLoggedIn)
{
GetInfo();
}
else
{
Debug.Log("User cancelled login");
}
}
FB API returns json result, so you will need FacebookUser class to deserialize it.
class FacebookUser
{
public string id;
public string first_name;
public string last_name;
public string email;
}
public void GetInfo()
{
FB.API("/me?fields=id,first_name,last_name,email", HttpMethod.GET, result =>
{
if(result.Error != null)
{
Debug.Log("Result error");
}
var facebookUser = Newtonsoft.Json.JsonConvert.DeserializeObject<FacebookUser>(result.RawResult);
Debug.Log(" facebook id - " + facebookUser.id);
Debug.Log(" facebook first name - " + facebookUser.first_name);
Debug.Log(" facebook last name - " + facebookUser.last_name);
Debug.Log(" facebook email - " + facebookUser.email);
});
}
NOTE: You should have Email permission from facebook to access it.
Check it in Graph API Explorer