Does anyone know how AdWhirl works?
I set up my custom event for Greystripe in which I initialize the SDK if it wasn't already initialized, and refresh the BannerView, but I don't see the custom event getting called. So my main question is, how and when does AdWhirl call the custom event? What are the rations and rollovers? I haven't done anything with them (mainly because I don't know why I need them. What does AdWhirl do with them?)
Also, how do I control when AdWhirl refreshes my banner? I'd like to tie the refresh with a button action.
I've been searching online nonstop for the past two days and read a lot of tutorials and example Java classes that people have shared, but none of them have worked. It just looks like AdWhirl is stagnate. It's so unclear to me how AdWhirl works beyond: it mediates between the app and all the ad opportunities you want to use in your ad. That's an entirely too high-level understanding for me to move forward. :(
Have you read the wiki page that describes how to use Custom Events? You basically create a custom event in the backend UI which behaves like another ad network, and you can configure it's traffic. Then you can implement the function name that you named in the backend. The only unintuitive part is that you have to implement AdWhirlInterface to listen for the custom event, which means creating an adWhirlGeneric() method. This method can be empty though, I am not seeing it called when creating my own test event. Finally, make sure to set the AdWhirlInterface.
So assuming on the backend you created a network with:
Name: Test Network
Function Name: testEvent
and gave it traffic (I recommend giving it 100% traffic when testing), then your code would look something like this:
public class MyActivity extends Activity {
...
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
...
}
...
public void testEvent() {
// Place event code here.
Log.d("Cust_Network", "Cust network got called!");
}
}
To control refreshing your ad, call rotateThreadedNow() on the AdWhirlLayout when a button is clicked, for example. This will take AdWhirl through the process of randomly determining a new ad network, and calling the correct adapter, or custom event in this case. If you choose to go this route, you may not want automatic refreshing, in which case you should disable automatic refreshing on the back end.
The ration object is populated with data from the configuration data. Each ration represents an ad network, and has keys which represent the individual ad network ids, weight percentages that you set in the backend, and backfill priority. Backfill priority is the network order that AdWhirl will request from if the original request did not fill. This process of going through backfill priority is called rollover. You will need to know a little bit about rollover when implementing your own custom event.
The wiki page mentioned has these recommendations to add to your custom event:
// In your custom event code, you'll want to call some of the below methods.
//
// On success:
// this.adWhirlLayout.adWhirlManager.resetRollover();
// this.adWhirlLayout.rotateThreadedDelayed();
//
// On failure:
// this.adWhirlLayout.rolloverThreaded();
If your custom event properly fetches an ad, you will want to reset the rollover order (so the next request will have the correct backfill order), and call rotateThreadedDelayed() so that a refresh will happen automatically in the amount of time you specified on the back end. If the ad request failed, you will want to call rolloverThreaded() so that AdWhirl can go through it's rollover process to check your other configured ad networks for ads.
if you want you can use an open source library i've developed that allows to use AdWhirl with other (unsupported) ad networks (but also with the officially supported ones). This library is also extensible, so you can add a new network to it and manage easily through AdWhirl.
The library is AdMAL (Ad Mediation Abstraction Layer) and is available on a github.com repository under the Apache 2.0 open source license: https://github.com/marcosiino/AdMAL
Using AdMAL you can easily implement AdWhirl in your applications for both supported and unsupported network (the integration is easiest than implementing AdWhirl SDK). Actually it only supports iOS (it's developed in Objective-C), but i plan to port to android in the next months.
I started AdMAL for my own purposes, then decided to release it to the public under an open source license some days ago. Hope this help! I encourage other developers to improve the library and implement new networks support, so that this can benefit to everyone.
Related
I tried AppBrain banner ads on my app recently. I am not sure if the ads are showing properly. This is what I see in my app
![Ads in my app]https://imgur.com/a/Pqwnw6q
The add seems like a generic template whereas, their website shows different images for a sample of banner ads.
![Sample ads in AppBrain website]https://imgur.com/a/IkSvdUj
The documentation says adding the view alone will automatically call the requestAd() function
public void requestAd()
Request an ad to be fetched. If a listener was set on this banner, that listener will be notified of the result. This method is automatically called once the banner is added to the view layout, so calling it manually is optional.
However, I did call the requestAd() in the activity also
AppBrainBanner banner;
In the onCreate
banner = findViewById(R.id.appBrainAdView);
banner.requestAd();
I contacted AppBrain 4-5 days ago and didn't receive any response yet. Am I implementing the ads right?
this is Mathijs from AppBrain.
Yes you're doing it right. The extra requestAd() is not needed, and our banners can show a number of different designs. The 'generic' one that requires a click before the user sees the apps he can install is the most common one, so it's normal you're seeing that one a lot.
I'm implementing the Facebook Audience Network SDK across iOS and Android. I set certain flags by checking a dictionary for the existence of an Ad, by looking up the Ads placementId. On iOS you can access this via the delegate methods easily, as below:
- (void)adView:(FBAdView *)adView didFailWithError:(NSError *)error
{
NSLog(#"Adview placement id is: %#", adView.placementId);
}
However on Android, the Ad object (in the Ad's listener) doesn't seem to have a placementId property as it's encapsulated. So this is either the usual inconsistencies between third-party SDK's cross platform, or i'm missing something?
Is it possible to retrieve the Ads placement id directly from the Ad object on Android, as you can do on iOS?
(Note: Facebook's docs don't seem to mention it)
Have you checked the AdView object in the Android implementation? it contains the placementId as well.
I'm trying to register users on my PlayBasis App using the Android SDK. However, it's not registering them.
The method
PlayerApi.register onSuccess()
is being called but the users never get registered. They don't show on the dashboard and when I try to get them I receive
RequestError{message='User doesn't exist', errorCode=200}
Can you recommend any other gamification platform that offer low price for small/indie apps?
I have investigated the case and found that
you actually can registered 7 players into our system on 24 September.
And this would also explain why Android SDK fires onSuccess().
However, it is like the problem is that you cannot find those players.
Just want to verify with you first that for getting detail of player,
you should supply "player_id", NOT "username".
Lastly, on "User" menu on the dashboard, you are going to find
only the list of dashboard users, NOT the list of players.
Best Regards,
Thanakij
Is there a way to disable iOS and Android apps which are live, for a few hours and add some custom message to all users, Can this be done through itunesconnect for Apple or google developer console for andorid.
Note :- i dont want to release new Apps / change existing code.
max
I know you mentioned you don't want to release new apps or change existing code, but unfortunately for this level of customization you'll have to (to start!) There's no push of a button to do this for you for either dashboard.
There's multiple ways of doing this and there's no official documentation out there, so if this answer gets accepted by the OP still look around at other answers on this thread.
My approach is to listen to an endpoint that you create, may it be from dropbox, s3, parse, etc. that have certain key-value pairs that your application can retrieve and handle appropriately. To the level of customization is up to you.
Let's do the example of your "we're temporarily unavailable" idea. Have the endpoint do the following:
{
"unavailable" : false,
"unavailable_text" : "Sorry we'll be back shortly!"
}
Now on app start up you listen to this endpoint. One day the unavailable key will be true, when that happens in the success handler for the endpoint you'll put in some logic to present a UnavailableViewController of sorts that might have a UILabel called descriptionLabel
if ([json valueForKey:#"unavailable"]) {
UnavailableViewController* controller = [[UnavailableViewController alloc] init];
controller.descriptionLabel.text = ([json valueForKey:#"unavailable_text"]) ? [json valueForKey:#"unavailable_text"] : #"We're temporarily unavailable, please try again later."; // just in case you forget to set it have a fallback.
// present view controller...
}
Hope this helps! Let me know in comments of any questions/concerns.
Google provides a convenient API to implement "in-app purchase" features on an Android app.
Along with these docs, there is also a dedicated chapter regarding the security level of this system and the good ways to design it.
The web is full of articles about this step, from public key protection to remote server validation, but I really can't understand why all of these techniques should work when the main problem is, simply, code hacking.
Maybe there is a better term to explain it, but let me do a quick example. The basic idea of my application is that, at certain points, the user can't proceed unless he has purchased an item.
Something like:
public void accessTheVeryCoolFeature() {
boolean haveIt = checkIfPurchased("verycoolfeature");
if (haveIt) {
// YEAH! let's open this very cool feature I paid 200 bucks for
}
else {
// ok... where is my wallet?
boolean purchased = startPurchaseFlow("verycoolfeature");
if (purchased) {
// my wallet is now empty but happy
}
}
}
Following the previous guidelines, the developer can protect his app during the purchase process, letting the startPurchaseFlow method to query a remote, trusted, server that validates the receipt.
Purchases done using a "fake marketplace" should be avoided by this.
Another method is to protect the unlocked content by obfuscating the code. This is really simple with tools like ProGuard and should make the life of an "hacker" a bit harder.
Now, I tried to act the part of an hacker that want to read my code, especially the billing phase.
It took me like 1 minute to spot the code I wrote in the previous example. Now the best part: what if I edit the (obfuscated) source code to do this?
public void atvf() {
boolean hi = cip("verycoolfeature");
hi = true; // <------------------------ AHAH!
if (hi) {
// YEAH! let's open this very cool feature for free
}
// ...
}
All the good words about remote verification and code obfuscation are totally gone. So why spend hours on trying to implement them when the very first problem is in a boolean value?
Am I missing something?
Unless your app is heavily dependent on its functionality being in a server - as in each functionality stays on the server and the app is just a client tool to call those server APIs, there is nothing you can do. If indeed it's a server-based app - you can check each incoming request (e.g. the app can send a one time session hash) if a valid transaction exists for it and is paid. If not, deny the request.
The app's code is running on the client's phone. If the hacker gains access to that code and is free to modify it to override any billing validations - there is nothing you can do. You should make sure he doesn't gain access to that source code in the first place.