I'm using Flash CS6 to build apps for iOS and Android.
I have built 6 working apps and in-app purchases and restoring was working properly. Now, I'm building my 7th app and I tested my in-app purchases. Purchasing works very well but when I remove the app and re-install and come to buy a product. It tells that I have already purchases the product and it will restore it for free, but it keeps loading and nothing happens.
This happened for all old apps as well.
*Note: I publish the SWF using Flash then I build the IPA using cmd
I use this as3 code:
function log(s:String):void
{
trace(s);
log_txt.text = s;
}
function initStorekit():void
{
log("initializing StoreKit..");
if (! StoreKit.isSupported())
{
log("Store Kit iOS purchases is not supported on this platform.");
return;
}
else
{
supported = true;
}
StoreKit.create();
log("StoreKit Initialized.");
// make sure that purchases will actually work on this device before continuing!
// (for example, parental controls may be preventing them.)
if (! StoreKit.storeKit.isStoreKitAvailable())
{
log("Store is disabled on this device.");
return;
}
// add listeners here
StoreKit.storeKit.addEventListener(StoreKitEvent.PRODUCT_DETAILS_LOADED,onProductsLoaded);
StoreKit.storeKit.addEventListener(StoreKitEvent.PURCHASE_SUCCEEDED,onPurchaseSuccess);
StoreKit.storeKit.addEventListener(StoreKitEvent.PURCHASE_CANCELLED,onPurchaseUserCancelled);
StoreKit.storeKit.addEventListener(StoreKitEvent.TRANSACTIONS_RESTORED, onTransactionsRestored);
// adding error events. always listen for these to avoid your program failing.;
StoreKit.storeKit.addEventListener(StoreKitErrorEvent.PRODUCT_DETAILS_FAILED,onProductDetailsFailed);
StoreKit.storeKit.addEventListener(StoreKitErrorEvent.PURCHASE_FAILED,onPurchaseFailed);
StoreKit.storeKit.addEventListener(StoreKitErrorEvent.TRANSACTION_RESTORE_FAILED, onTransactionRestoreFailed);
// initialize a sharedobject that's holding our inventory.;
initSharedObject();
var productIdList:Vector.<String>=new Vector.<String>();
productIdList.push(LEVELPACK1_ID);
productIdList.push(LEVELPACK2_ID);
productIdList.push(LEVELPACK3_ID);
productIdList.push(REMOVEADS_ID);
productIdList.push(ALLINPACKAGE_ID);
// when this is done, we'll get a PRODUCT_DETAILS_LOADED or PRODUCT_DETAILS_FAILED event and go on from there...;
log("Loading product details...");
StoreKit.storeKit.loadProductDetails(productIdList);
}
function onProductsLoaded(e:StoreKitEvent):void
{
log("products loaded.");
for each (var product:StoreKitProduct in e.validProducts)
{
trace("ID: "+product.productId);
trace("Title: "+product.title);
trace("Description: "+product.description);
trace("String Price: "+product.localizedPrice);
trace("Price: "+product.price);
}
log("Loaded "+e.validProducts.length+" Products.");
// if any of the product ids we tried to pass in were not found on the server,
// we won't be able to by them so something is wrong.
if (e.invalidProductIds.length > 0)
{
log("[ERR]: these products not valid:"+e.invalidProductIds.join(","));
return;
}
}
function onProductDetailsFailed(e:StoreKitErrorEvent):void
{
log("ERR loading products:"+e.text);
}
function initSharedObject():void
{
this.sharedObject = SharedObject.getLocal("myPurchases");
// check if the application has been loaded before. if not, create a store of our purchases in the sharedobject.
if (sharedObject.data["inventory"] == null)
{
sharedObject.data["inventory"]=new Object();
}
updateInventoryMessage();
}
/** Update Inventory Message */
function updateInventoryMessage():void
{
var inventory:Object = sharedObject.data["inventory"];
// if the value is set to something, you have it
if (inventory[LEVELPACK1_ID] != null)
{
unlockLP1_fnc();
}
if (inventory[LEVELPACK2_ID] != null)
{
unlockLP2_fnc();
}
if (inventory[LEVELPACK3_ID] != null)
{
unlockLP3_fnc();
}
if (inventory[REMOVEADS_ID] != null)
{
hideAds_fnc();
}
if (inventory[ALLINPACKAGE_ID] != null)
{
unlockLP1_fnc();unlockLP2_fnc();unlockLP3_fnc();hideAds_fnc();
}
log("Has hasUnlocked? ");
}
function purchaseUnlock(s:String):void
{
enableLoading();
// for this to work, you must have added the value of LEVELPACK_PRODUCT_ID in the iTunes Connect website
log("start purchase of non-consumable '"+s+"'...");
// we won't let you purchase it if its already in your inventory!
var inventory:Object = sharedObject.data["inventory"];
if (inventory[s] != null)
{
log("You already have unlocked this!");
return;
}
StoreKit.storeKit.purchaseProduct(s);
}
/** Example of how to restore transactions */
function restoreTransactions():void
{
enableLoading();
log("requesting transaction restore...");
StoreKit.storeKit.restoreTransactions();
}
function onPurchaseSuccess(e:StoreKitEvent):void
{
log("Successful purchase of '"+e.productId+"'");
disableLoading();
// update our sharedobject with the state of this inventory item.
// this is just an example to make the process clear. you will
// want to make your own inventory manager class to handle these
// types of things.
var inventory:Object = sharedObject.data["inventory"];
switch (e.productId)
{
case ALLINPACKAGE_ID :
inventory[ALLINPACKAGE_ID] = "purchased";
break;
case LEVELPACK1_ID :
inventory[LEVELPACK1_ID] = "purchased";
break;
case LEVELPACK2_ID :
inventory[LEVELPACK2_ID] = "purchased";
gotoAndStop("lvls");
break;
case LEVELPACK3_ID :
inventory[LEVELPACK3_ID] = "purchased";
gotoAndStop("lvls");
break;
case REMOVEADS_ID :
inventory[REMOVEADS_ID] = "purchased";
gotoAndStop("mm");
break;
default :
log("xxxxx");
// we don't do anything for unknown items.
}
// save state!
sharedObject.flush();
// update the message on screen;
updateInventoryMessage();
}
function onPurchaseFailed(e:StoreKitErrorEvent):void
{
disableLoading();
log("FAILED purchase="+e.productId+",t="+e.transactionId+",o="+e.originalTransactionId);
}
function onPurchaseUserCancelled(e:StoreKitEvent):void
{
disableLoading();
log("CANCELLED purchase="+e.productId+","+e.transactionId);
}
function onTransactionsRestored(e:StoreKitEvent):void
{
disableLoading();
log("All previous transactions restored!");
var inventory:Object = sharedObject.data["inventory"];
switch (e.productId)
{
case ALLINPACKAGE_ID :
inventory[ALLINPACKAGE_ID] = "purchased";
break;
case LEVELPACK1_ID :
inventory[LEVELPACK1_ID] = "purchased";
break;
case LEVELPACK2_ID :
inventory[LEVELPACK2_ID] = "purchased";
gotoAndStop("lvls");
break;
case LEVELPACK3_ID :
inventory[LEVELPACK3_ID] = "purchased";
gotoAndStop("lvls");
break;
case REMOVEADS_ID :
inventory[REMOVEADS_ID] = "purchased";
gotoAndStop("mm");
break;
default :
log("xxxxx");
// we don't do anything for unknown items.
}
// save state!
sharedObject.flush();
updateInventoryMessage();
}
function onTransactionRestoreFailed(e:StoreKitErrorEvent):void
{
disableLoading();
log("an error occurred in restore purchases:"+e.text);
}
Related
I'm creating a Game App in objective-c which is using Google Play Game services for realtime Multiplayer functionality. I follows the documentation at https://developers.google.com/games/services/ios/turnbasedMultiplayer. In my app there are two options Auto match and Invite Match. Auto Match functionality working fine. But Invite match not.
I follow following Code for this
- (int)minPlayersForPlayerPickerLauncher {
return 1;
}
- (int)maxPlayersForPlayerPickerLauncher {
return 2;
}
- (IBAction)inviteFriendsWasPressed:(id)sender
{
// This can be a 2-4 player game
[GPGLauncherController sharedInstance].playerPickerLauncherDelegate = self;
// This assumes your class has been declared a GPGPlayerPickerLauncherDelegate
[[GPGLauncherController sharedInstance] presentPlayerPicker];
}
on click this button Action follow Screen is open
See here
After that when I enter emailId in textfield there is no action perform to search particular user.
Please help me
Thanks
Unfortunately, the player selection no longer works since Google+ is no longer integrated into Play Game Services: https://android-developers.googleblog.com/2016/12/games-authentication-adopting-google.html
// request code for the "select players" UI
// can be any number as long as it's unique
final static int RC_SELECT_PLAYERS = 10000;
// launch the player selection screen
// minimum: 1 other player; maximum: 3 other players
Intent intent = Games.RealTimeMultiplayer.getSelectOpponentsIntent(mGoogleApiClient, 1, 3);
startActivityForResult(intent, RC_SELECT_PLAYERS);
#Override
public void onActivityResult(int request, int response, Intent data) {
if (request == RC_SELECT_PLAYERS) {
if (response != Activity.RESULT_OK) {
// user canceled
return;
}
// get the invitee list
Bundle extras = data.getExtras();
final ArrayList<String> invitees =
data.getStringArrayListExtra(Games.EXTRA_PLAYER_IDS);
// get auto-match criteria
Bundle autoMatchCriteria = null;
int minAutoMatchPlayers =
data.getIntExtra(Multiplayer.EXTRA_MIN_AUTOMATCH_PLAYERS, 0);
int maxAutoMatchPlayers =
data.getIntExtra(Multiplayer.EXTRA_MAX_AUTOMATCH_PLAYERS, 0);
if (minAutoMatchPlayers > 0) {
autoMatchCriteria = RoomConfig.createAutoMatchCriteria(
minAutoMatchPlayers, maxAutoMatchPlayers, 0);
} else {
autoMatchCriteria = null;
}
// create the room and specify a variant if appropriate
RoomConfig.Builder roomConfigBuilder = makeBasicRoomConfigBuilder();
roomConfigBuilder.addPlayersToInvite(invitees);
if (autoMatchCriteria != null) {
roomConfigBuilder.setAutoMatchCriteria(autoMatchCriteria);
}
RoomConfig roomConfig = roomConfigBuilder.build();
Games.RealTimeMultiplayer.create(mGoogleApiClient, roomConfig);
// prevent screen from sleeping during handshake
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
}
// create a RoomConfigBuilder that's appropriate for your implementation
private RoomConfig.Builder makeBasicRoomConfigBuilder() {
return RoomConfig.builder(this)
.setMessageReceivedListener(this)
.setRoomStatusUpdateListener(this);
}
I am creating a Pebble companion app for an iOS application. I have setup my AppSync with some initial values:
Tuplet initial_values[] = {
TupletCString(SYNC_KEY_LANGUAGE, language),
TupletCString(SYNC_KEY_TOTAL_AMOUNT, totalAmount),
TupletCString(SYNC_KEY_TODAY_AMOUNT, todayAmount),
TupletCString(SYNC_KEY_TRIP_NAME, tripName)
};
app_sync_init(&sync, sync_buffer, sizeof(sync_buffer), initial_values,
ARRAY_LENGTH(initial_values), sync_tuple_changed_callback,
sync_error_callback, NULL);
The problem is that when I push new data from my iPhone, the initial values are getting set to my text layers, instead of the data sent:
static void sync_tuple_changed_callback(const uint32_t key, const Tuple* new_tuple, const Tuple* old_tuple, void* context) {
switch (key) {
case SYNC_KEY_TRIP_NAME: {
text_layer_set_text(tripNameLayer, new_tuple->value->cstring);
layer_mark_dirty((Layer *)tripNameLayer);
}
break;
case SYNC_KEY_TOTAL_AMOUNT: {
text_layer_set_text(totalAmountLayer, new_tuple->value->cstring);
layer_mark_dirty((Layer *)totalAmountLayer);
}
break;
case SYNC_KEY_TODAY_AMOUNT: {
text_layer_set_text(todayAmountLayer, new_tuple->value->cstring);
layer_mark_dirty((Layer *)todayAmountLayer);
//storeData(STORAGE_KEY_TODAY_AMOUNT, (char *)new_tuple->value->cstring);
}
break;
case SYNC_KEY_LANGUAGE: {
// DO NOTHING
}
break;
default: {
debugMessage("default case");
}
break;
}
}
This is the code I am using from the iPhone side:
NSDictionary *tripInfo = #{
#(SyncKeyTripName) : #"Denver",
#(SyncKeyLanguage) : #"en",
#(SyncKeyTotalAmount) : #"154.43",
#(SyncKeyTodayAmount) : #"23.50"
};
[self.watch appMessagesPushUpdate:tripInfo
onSent:^(PBWatch *watch, NSDictionary *update, NSError *error) {
if (error) {
NSLog(#"error sending update! %#", error);
} else {
NSLog(#"update: %#", update);
}
}];
I have setup my watch buttons to clear out any values in those layers, this is how I know when the app is getting updates from the phone.
Why is AppSync continually using old data, instead of new data?
Turns out this behavior is exhibited when calling the app_sync_init function more than once. For some reason I had it being called twice when the application is being setup. Once I removed the extraneous call, my callbacks contained the new data, not the initial.
I am developing cocos2d-x game which have online game mode.
Online game designed and implemented by Photon Cloud SDK(http://www.exitgames.com).
I implemented only ios version but it doesn't work.
The codes that I have implemented are blow.
void NetworkLogic::opJoinRandomRoom()
{
ExitGames::Common::JVector<ExitGames::LoadBalancing::Room> roomList;
roomList = mLoadBalancingClient.getRoomList();
int count = roomList.getSize();
CCLog("Room Count = %d", count);
if(count == 0)
{
this->opCreateRoom();
}else{
mLoadBalancingClient.opJoinRandomRoom();
}
}
void NetworkLogic::update(float dt)
{
this->run();
}
void NetworkLogic::run(void)
{
if(mLastInput == INPUT_EXIT && mStateAccessor.getState() != STATE_DISCONNECTING && mStateAccessor.getState() != STATE_DISCONNECTED)
{
disconnect();
mStateAccessor.setState(STATE_DISCONNECTING);
}
else
{
State state = mStateAccessor.getState();
switch(state)
{
case STATE_INITIALIZED:
connect();
mStateAccessor.setState(STATE_CONNECTING);
break;
case STATE_CONNECTING:
break; // wait for callback
case STATE_CONNECTED:
{
ExitGames::Common::JVector<ExitGames::LoadBalancing::Room> roomList;
roomList = mLoadBalancingClient.getRoomList();
int count = roomList.getSize();
ExitGames::Common::JString tmp;
tmp = count;
EGLOG(ExitGames::Common::DebugLevel::INFO, tmp);
CCLog("Room count in Room = %d", count);
switch(mLastInput)
{
case INPUT_CREATE_GAME: // create Game
opCreateRoom();
break;
case INPUT_JOIN_RANDOM_GAME: // join Game
opJoinRandomRoom();
mStateAccessor.setState(STATE_JOINING);
break;
default: // no or illegal input -> stay waiting for legal input
break;
}
break;
}
case STATE_JOINING:
break; // wait for callback
case STATE_JOINED:
switch(mLastInput)
{
case INPUT_LEAVE_GAME: // leave Game
mLoadBalancingClient.opLeaveRoom();
mStateAccessor.setState(STATE_LEAVING);
break;
default: // no or illegal input -> stay waiting for legal input
break;
}
break;
case STATE_LEAVING:
break; // wait for callback
case STATE_LEFT:
mStateAccessor.setState(STATE_CONNECTED);
break;
case STATE_DISCONNECTING:
break; // wait for callback
default:
break;
}
}
mLastInput = INPUT_NON;
mLoadBalancingClient.service();
}
First I run one app then getRoomList function returns 0 values.
Also after first room created and run second app but it also returns getRoomList function 0.
Please help me.
I have just taken the code that you have provided in your question and copied it into the according place inside the demo of an otherwise unchanged version 3.2.2.0 build of the Photon C++ Client SDK (and removed the two CCLog() lines to make it compile without cocos2d-x) and it worked just fine for me:
The demo prints 0 for the size of the room list until I let one client create a room. Afterwards the other client prints 1.
Basically I am trying to connect to Facebook using actionscript 3.0. If I were to run the application in Facebook, and it is connected to Facebook, the stamp image would be added to the screen. The codes below are the functions used:
private var facebookAppID:String = "myappID";
private var fbLoggedIn:Boolean = false;
public function tryout() {
Facebook.init(facebookAppID, onInit);
FBConnect();
}
protected function onInit(result:Object, fail:Object):void {
if (result) { //already logged in because of existing session
fbLoggedIn = true;
} else {
fbLoggedIn = false;
}
}
public function FBConnect():void {
trace("in FBConnect");
if (fbLoggedIn)
{
showFbForm();
trace("success logged in");
}
else
{ // attempt to request for login
var opts:Object = {scope:"publish_stream, email"};
Facebook.login(onLogin, opts);
trace("failed logged in");
}
}
protected function onLogin(result:Object, fail:Object):void {
trace("in onLogin");
if (result) { //successfully logged in
fbLoggedIn = true;
showFbForm();
} else {
fbLoggedIn = false;
return;
}
}
protected function showFbForm():void {
addChild(stamp1);
stamp1.x = 0;
stamp1.y = 0;
trace("in showFBForm()");
}
The stamp1 should be displayed on the stage. However, nothing is displayed at all. I have been trying and researched but it still does not display.
I don't know if you're hiding your app ID or you just filled in MyAppID as your appID,
but if it's the second then it won't work because that appID does not exist. You need to find your appID in your facebook dashboard.
Since your code can't connect to the appID, it won't show any content because the content of "myAppID" is null.
I'd like my user to take a picture as an attachment by using the built in camera.
Is there someway to invoke the camera on a button press and save the resulting taken picture?
The other option is to use the BlackBerry Invoke API to start the native camera application and listen for a file system event:
Invoke.invokeApplication(Invoke.APP_TYPE_CAMERA, new CameraArguments());
then, later:
class FileExplorerDemoJournalListener implements FileSystemJournalListener {
public void fileJournalChanged() {
long nextUSN = FileSystemJournal.getNextUSN();
for (long lookUSN = nextUSN - 1; lookUSN >= _lastUSN && msg == null; --lookUSN) {
FileSystemJournalEntry entry = FileSystemJournal.getEntry(lookUSN);
if (entry == null) {
break;
}
String path = entry.getPath();
if (path != null) {
if (path.endsWith("png") || path.endsWith("jpg") || path.endsWith("bmp") || path.endsWith("gif") ){
switch (entry.getEvent()) {
case FileSystemJournalEntry.FILE_ADDED:
//either a picture was taken or a picture was added to the BlackBerry device
break;
case FileSystemJournalEntry.FILE_DELETED:
//a picture was removed from the BlackBerry device;
break;
}
}
}
}
}
}
Finally...
Application.addFileSystemJournalListener(new FileExplorerDemoJournalListener());
This will get you most of the way there... taken from: http://docs.blackberry.com/en/developers/deliverables/11942/Detect_when_img_is_added_or_removed_file_system_740288_11.jsp
http://docs.blackberry.com/en/developers/deliverables/17968/Take_a_picture_in_a_BB_device_app_1228201_11.jsp