What is the proper way to create user invite codes using Branch? - android

I've been combing through the Branch.io Android docs and haven't come up with how to create user invite codes. I've gotten the basic Branch referral system working ok, but I'd like to assign each user a custom invite code similar to what you see with Uber and Airbnb.
My current implementation looks like this:
mSmsBranchUniversalObject = new BranchUniversalObject()
.setCanonicalIdentifier("invite/sms")
.setTitle(getString(R.string.simple_share_title))
.setContentDescription(getString(R.string.default_share_desc))
.addContentMetadata("userId", mUserId);
mSmsLinkProperties = new LinkProperties()
.setChannel("sms")
.setFeature("sharing");
mSmsBranchUniversalObject.generateShortUrl(getActivity(), mSmsLinkProperties, new Branch.BranchLinkCreateListener() {
#Override
public void onLinkCreate(String url, BranchError error) {
if (error == null) {
mSmsShareLink = url;
}
}
});
#OnClick(R.id.iv_sms)
public void smsShare() {
Branch.getInstance(getActivity()).userCompletedAction(BranchEvent.SHARE_STARTED);
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("sms:"));
intent.putExtra("sms_body", getString(R.string.share_sms, mSmsShareLink));
startActivity(intent);
}
The following implementation gets me a link that looks something like this:
https://mydomain.app.link/A1BCdEf2gH
But I'd like to share something like: ADAM98 (see screenshot above), and have the user enter it at checkout etc.
Now creating an invite code manually for each user isn't much work, I could take the 1st four characters of the user's username and append some random characters to it. But then what do I do with it? I assumed that I would simply need to pass this code to .setAlias(mUserInviteCode) on mSmsLinkProperties.
Am I on the right track here? What is the proper flow to implement this? How do you handle this invite code once received on the install?

Alex from Branch.io here.
We actually used to offer a referral code feature exactly as you've described, but deprecated it a while back in favor of a referral link system. The reason why is actually quite interesting: our partner apps found codes unnecessary and a lot of extra work. The way Branch handles referrals is fundamentally different and far more user-friendly, so you actually don't need to make the user enter a code at all.
Traditional app referral process
Inviting User gets a code
Inviting User gives a code to a friend (Invited User) and says 'go download this app and enter my code!'
Invited User hopefully downloads the app, hopefully finds out how to enter a code, hopefully enters the code correctly
Inviting User gets a reward
As you can see, plenty of places where that process can go wrong.
Branch referral process
Inviting User gets a link
Inviting User sends the link to a friend (Invited User)
Invited User clicks the link, is sent directly to the Play Store, downloads the app, and automatically triggers the referral redemption logic without any manual work
Inviting User gets a reward
This works because Branch tracks the user who originally created the link, and can report back on that when the new user successfully downloads/purchases/whatever else the first time after opening the link. It is a much simpler and more seamless process, and the Branch referral infrastructure is so reliable that it 'just works'.
Here is the documentation page for setting this up: https://dev.branch.io/features/referral-programs/

Related

Facebook Deep Link Tester Works, Ad Doesn't

Pretty straightforward situation: I'm doing deferred deep links for Facebook ads and have successfully tested them via the Deep Link Tester found here (to be clear I do also select "Send Deferred".) However, putting the app into production, even though I am certain that the app has received new launches via ads, the deferred deep link code returns null. Testing it via an Ad Preview is broken as well.
I'm not getting any errors logged from the Facebook SDK and I have confirmed that both the application id and the client token exist when I make the fetchDeferredAppLinkData call.
I've exhausted StackOverflow/Facebook/Google for possible solutions or reasons why there would be a difference between the Deep Link Tester and the actual ad, but have 0 clue. Any direction or thoughts would be really helpful, thanks so much!
For reference, here's the code I'm using to handle the deferred deep link:
AppLinkData.fetchDeferredAppLinkData(cordova.getActivity().getApplicationContext(),
new AppLinkData.CompletionHandler() {
#Override
public void onDeferredAppLinkDataFetched(AppLinkData appLinkData) {
if(appLinkData != null) {
//Handling link
}
}
}
);
EDIT: It looks like we're now getting the fetchDeferredAppLinkData to return values in production, this was after saving the client token in onCreate. However, Ad Previews still don't work in testing; is this by design? Are Ad Previews not intended to be fully-functional and thus shouldn't be used for this purpose?

Logout from Spotify with the sdk spotify-android-auth

I have an Android app, which the user can link to Spotify, with :
AuthenticationClient.openLoginActivity(getActivity(), SPOTIFY_REQUEST_CODE, request);
The problem is that I want the user to change his Spotify account so I want to logout the user from Spotify to log with another account. But the data of the connection are saved in the cache and when I use this line again :
"AuthenticationClient.openLoginActivity(getActivity(), SPOTIFY_REQUEST_CODE, request);", it does not show the connection dialog because the user is already connected.
In the doc, it says :
"To log out and clear all stored tokens, use the AuthenticationClient#clearCookies method. Both Spotify and Facebook tokens will be removed."
But the method clearCookies does not exist anymore. What can I do to logout the user and allow him to connect on another account ?
I've searched on the net and seems that this code
AuthenticationRequest.Builder builder = new AuthenticationRequest.Builder(CLIENT_ID, type, redirectUri)
.setShowDialog(true)
.setScopes(scopes).build();
took from this post it's your only choice to try to logout a user.
I can't test it, so you should try it yourself and see if works.
The documentation on the Spotify Android SDK is outdated and is not reflecting the new Spotify auth library on GitHub.
Spotify's Android SDK documentation is definitely outdated. My observation is that when you call
AuthorizationClient.clearCookies(context)
directly before starting Spotify's auth activity, it just works fine. But if you call it once and then expect that the user is logged out, when you start the activity later in the future, cached credentials keep messing around.
I do not prefer
builder.setScopes(arrayOf("")).setShowDialog(false).build()
as it shows you a "not you? Click to log out" option. So basically you need to log out on the Spotify UI, cannot do it from code.
In my case, the application saves the logged in user's email (I need that to show on the UI, anyway). When I want to log the user out programmatically, I just delete the saved email from the app and call
clearCookies()
when I start Spotify's Activity if the variable is empty.
A bit late, but you can use this AuthorizationClient.clearCookies(this) as
AuthenticationClient no longer exists

How I ask to user to rate the app and share it on facebook

I'm in the final stages of a project (my first project), but I'm stumbling in some points yet.
Like:
I want to ask the user to rate the app and also share it on facebook, but not only this, after I need also check if he/she really did this, and how many stars he/she rated the app.
I found this answer to ask the user to rate the app:
/* inside an activity */
final Uri uri = Uri.parse("market://details?id=" + getApplicationContext().getPackageName());
final Intent rateAppIntent = new Intent(Intent.ACTION_VIEW, uri);
if (getPackageManager().queryIntentActivities(rateAppIntent, 0).size() > 0)
{
startActivity(rateAppIntent);
}
else
{
/* handle your error case: the device has no way to handle market urls */
}
Seems to me a easy way, but how my app wasn't published yet, I have no way to test... And I don't know how it works (and if it works), this show a kind of native dialog? Anyone already did this way? And how I can check if a user really rated the app and how many stars the user gave programmatically? I need this answer to run a code.
And to share I can use a intent, ok, but and then, how I check if the user really shared it?
Any tip or link to any example will be very welcome.
Firstly as far as I know.. It's not possible to check if user have rated your app or not. You can google that to know the reasons. Best approach is to count launches of app by user ( ideally #5 ) then show dialog asking user rate app. You can use this tool https://github.com/delight-im/AppRater
Regarding sharing .. its similar.. Normally it should not be allowed. My favorite approach is to track user posting by injecting user data (hashed) to a link inside the post content and track clicking. You may shorten link. There are many tools to do so such as Bit.ly, use this lib to achieve that on android https://github.com/dextorer/Bitlyzer
I hope that may help,'.

"Page not found" when a user clicks on a Facebook invite from my application

I'm not sure if this is a programming related problem or not, but as I have no experience with the Facebook SDK I'm just assuming that I did something wrong somewhere, even though I've followed the documentation to the T.
I am using the Unity SDK for anybody that is curious, and I am using the FB.AppRequest to send the invite to the application, the code in my application looks exactly like that in the documentation.
public void InviteFriends() {
FB.AppRequest(
message: "Come play this great game!",
callback: LogCallback
);
}
void LogCallback(FBResult result) {
Debug.Log("Callback was called: " + result.Text);
}
This brings up the box as expected and allows me to invite a friend, and the friend does get the invite, however once they click on the invite they are redirected to a page that looks like this:
Which is causing quite a bit of problems for me; I've checked everything in the application panel and it seems like everything checks out. My google play identifier is correct as-well as my Class Name. My key hashes are all correct. I don't know what else I can do. If you'd like to look up my bundle identifier on the play store it's buzz.qualify and I'm sure that you'll find it with ease.
I should also add that I have an application page which can be found here: https://www.facebook.com/pages/Qualify/1647231425506903?fref=ts
This page is linked to the facebook application in the developer console as-well.
What can I do to resolve this issue? Is it in the code? Please help, this has been a 4 day long set-back and we're losing progress rapidly because of it.
It's been a few days now, we're now paying someone for a fix through paypal.
Do you have Canvas App setup on Facebook for your Android Game?
If not, read
Requirements for Invitable Friends.
It states that your game request will...
direct recipients to one of the following places:
Your app on Facebook Canvas.
Your native app on iOS or Android, if installed.
The Apple App Store or Google Play, if not installed.

in-app billing basics for beginner

some might remember me from previous questions. I'm building an app for Android and it's going well. Most of the functions I wanted work great. I learned the basics by myself (and with the help of a few generous people here on StackOverflow!) but I still consider myself a beginner (today's question will show you how much of a beginner I am!).
My app is a dynamic map that shows the history of a country at a specific point in time. On Google Play, the user can download for free the base app (mostly empty), then he can buy packs (France, USA, UK, etc.) with in-app billing. That's where I am stuck.
I've bought the Milkman AndroidIAB ANE and read carefully the documentation (this one). I've managed to add the ANE to my library and update my application manifest. I've modified the example file to add my public key and the IDs for the purchasable packs. (I don't post the code here because I don't know if I'm allowed since the ANE is licensed.)
My app works that way:
First screen : Logo with a link to the website and a "Enter" button.
When clicked, the user arrive on a screen with a few buttons (one for each pack/country).
If the user click on a pack he owns, he is send to the chosen country's map.
If he doesn't own it, he is asked if he'd like to buy it and send to buy it.
Problems: (warning: some of those are worthy of noob of the month status, but I'm here to learn right?)
The code adapted from the Milkman's example is in an outside .as file used as DocumentClass.How do I link my screen 2 buttons with the functions from the .as file?
I tried this, but it doesn't work:
franceBtn.addEventListener(MouseEvent.CLICK, checkAndPurchase);
function checkAndPurchase (e:MouseEvent):void{
purchasePack1();
//function from the example, it checks if the pack is owned
// and send the user to the store if not
};
EDIT 1: It is probably really easy to do, but I'm just not experienced enough to understand what I need to do I guess.
I have a series of buttons in my app (say "franceBtn", "usaBtn" and "ukBtn"). Those buttons, when clicked, need to check if the pack ("francePack", "usaPack" and "ukPack") is owned by the user and if it is not, start the in-app purchase. I have tried to add an EventListener to the buttons, but nothing happens. Not on screen, not in the log.
2.Let's say the problem 1 is fixed. My app is meant to be used offline (except for buying additional packs). The way I understood what I read is that the "inventory" of in-app purchased packs is obtained via Google Play, which means (if I'm not mistaken) that the user needs to be online. Is there a way to create a file of some kind inside the device that stores this "inventory" so it can be accessed offline?
EDIT 2: I want the user to be able to use the app from everywhere, without the need to be online (except for purchasing packs obviously). But I guess that the app checks with Google Play in order to know which pack is already owned. So I'm looking for a way to store the "inventory" of owned packs directly inside the device/app (so it can be accessed offline and updated everytime internet starts.
I hope it is more clear, and thank you for pointing out it was not.
I've read the doc quite a few times, and I'm really stuck, so please, I'd really appreciate any help. ;)
Thanks in advance,
Jeryl
EDIT 3: Here is the portion of my code relating to IAB (made by following this tutorial :here but I didn't really understand it. I'm willing to learn but this is an intermediate level tuto, and I've found nothing on Internet that explains what to do for real beginners. If you have links I couldn't find, I'm all hears :D )
import com.milkmangames.nativeextensions.android.*;
import com.milkmangames.nativeextensions.android.events.*;
import flash.events.MouseEvent;
if (AndroidIAB.isSupported()) {
AndroidIAB.create();
}
// listeners for billing service startup
AndroidIAB.androidIAB.addEventListener(AndroidBillingEvent.SERVICE_READY, onReady);
AndroidIAB.androidIAB.addEventListener(AndroidBillingEvent.SERVICE_NOT_SUPPORTED, onUnsupported);
// start the service
AndroidIAB.androidIAB.startBillingService("my_key");
function onReady(e: AndroidBillingEvent): void {
trace("service now ready- you can now make purchases.");
}
function onUnsupported(e: AndroidBillingEvent): void {
trace("sorry, in app billing won't work on this phone!");
}
// listen for inventory events
AndroidIAB.androidIAB.addEventListener(AndroidBillingEvent.INVENTORY_LOADED, onInventoryLoaded);
AndroidIAB.androidIAB.addEventListener(AndroidBillingErrorEvent.LOAD_INVENTORY_FAILED, onInventoryFailed);
function onInventoryLoaded(e: AndroidBillingEvent): void {
for each(var purchase: AndroidPurchase in e.purchases) {
trace("You own the item:" + purchase.itemId);
}
}
function onInventoryFailed(e: AndroidBillingErrorEvent): void {
trace("Something went wrong loading inventory: " + e.text);
}
// load the player's current inventory
AndroidIAB.androidIAB.loadPlayerInventory();
// listen for purchase events
AndroidIAB.androidIAB.addEventListener(AndroidBillingEvent.PURCHASE_SUCCEEDED, onPurchaseSuccess);
AndroidIAB.androidIAB.addEventListener(AndroidBillingErrorEvent.PURCHASE_FAILED, onPurchaseFailed);
function onPurchaseSuccess(e: AndroidBillingEvent): void {
var purchase: AndroidPurchase = e.purchases[0];
trace("you purchased the item " + purchase.itemId);
AndroidIAB.androidIAB.loadPlayerInventory();
}
function onPurchaseFailed(e: AndroidBillingErrorEvent): void {
trace("Something went wrong with the purchase of " + e.itemId + ": " + e.text);
}
franceBtn.addEventListener(MouseEvent.CLICK, onPackOneButtonClicked);
function onPackOneButtonClicked(e: MouseEvent) {
if (purchase.itemId == "packone") {
franceMap.visible = true;
} else {
AndroidIAB.androidIAB.purchaseItem("packone");
}
}
Thanks for your patience! Jeryl
Before proceeding, I am assuming that you have properly set up the products in IAP section of Google play.
Now for your first question, I am not sure about the problem as clicking on a button and something to be done on that event should have worked out of the box. Your code should be something along the lines:
( Assuming you have two packs and their itemIds are com.yourcomapny.packOne and com.yourcompany.packTwo)
franceBtn.addEventListener( MouseEvent.CLICK, onPackOneButtonClicked );
function onPackOneButtonClicked( event:MouseEvent )
{
if( !isPackOnePurchased() )
{
purchasePackOne();
}
}
// Similarly for pack two
This is pretty much the same code , you are trying to write. Perhaps we can help you more with your problem, if you can post some portion of the code which is not working.
For your second part, if you want to store the "inventory" information offline, you may proceed in the following way:
1) Lets say you create an empty file.
2) Lets say if a person buys com.yourcompany.packTwo and you received purchase Successful event, you just add com.yourcompany.packTwo to the file and thus marking it as purchased.
3) Whenever you call isPackOnePurchased or isPackTwoPurchased, it checks whether corresponding itemId is present in the file and decide whether this package needs to be bought or it is already bought.
This will get you started. Another thing for enhanced user experience and security is that whenever user clicks on a button to buy the pack ( and he/she is connected to the internet ), always check whether that pack is in the inventory or not and show the feedback according to that. Always sync your local state with inventory, if there is any inconsistency. The inconsistency may arise if user deletes their application data and then tries to open the pack. This check will ensure that your application is synced with server state.
If you want next level of security you can either encrypt the information( item Ids in this case ) and store it a secure database.
Encryption can be done using numerous encryption methods. One such method is Rijndael encryption. You can use this tool this online tool for generating encrypted strings for your itemIds. This will give you a feel of what I am trying to say.
For how to store information in local database in an AIR based applications, see this link from Adobe

Categories

Resources