I am facing some issues in Amazon In App Purchase in Live App Testing. I am stuck at this since last 4-5 days, tried a lots of solutions but not able to move further. I am using Amazon in app purchase SDK. I have taken sample project that comes with Amazon SDK. I have changed my SKU in it, For local testing i am usign App Tester and app is working fine. Now I have uploaded app on Live App testing and created IAP item on Amazon account then App on Live app testing stop working.
Activity onResume code is below-
#Override
protected void onResume() {
super.onResume();
sampleIapManager.activate();
Log.d(TAG, "onResume: call getUserData");
PurchasingService.getUserData();
Log.d(TAG, "onResume: getPurchaseUpdates");
PurchasingService.getPurchaseUpdates(false);
System.out.println(TAG + " onResume: call getProductData for skus: " + MySku.values());
final Set<String> productSkus = new HashSet<String>();
for (final MySku mySku : MySku.values()) {
System.out.println("TAG , SKU information = "+mySku.getSku());
productSkus.add(mySku.getSku());
}
PurchasingService.getProductData(productSkus);
}
SKU json that defined on store -
{
"com.amazon.sample.iap.subscription.mymagazine.quarter": {
"smallIconUrl": "https://com-amazon-mas-catalog.s3.amazonaws.com/amzn1.devportal.fileupload.6b3d68d2073e4bfb9f9d273448d51cc6_23d65d61-4fb7-44bd-b7c1-aeb6bc885981_09a3dbc2307fb170a718a981c150c1f1",
"title": "Subscription Plan",
"itemType": "SUBSCRIPTION",
"price": 12,
"description": "Subscription to My Magazine",
"languageTitleMap": {
"US": "Subscription Plan"
},
"languageDescriptionMap": {
"US": "Subscription to My Magazine"
},
"currencyPriceMap": {
"US": 0
},
"subscriptionParent": "com.amazon.sample.iap.subscription.mymagazine"
},
"com.amazon.sample.iap.subscription.mymagazine.month": {
"smallIconUrl": "https://com-amazon-mas-catalog.s3.amazonaws.com/amzn1.devportal.fileupload.6b3d68d2073e4bfb9f9d273448d51cc6_23d65d61-4fb7-44bd-b7c1-aeb6bc885981_09a3dbc2307fb170a718a981c150c1f1",
"title": "Subscription Plan",
"itemType": "SUBSCRIPTION",
"price": 5,
"description": "Subscription to My Magazine",
"languageTitleMap": {
"US": "Subscription Plan"
},
"languageDescriptionMap": {
"US": "Subscription to My Magazine"
},
"currencyPriceMap": {
"US": 0
},
"subscriptionParent": "com.amazon.sample.iap.subscription.mymagazine"
}
}
MySku.java in Code -
package com.example.sampleiap;
/**
*
* MySku enum contains all In App Purchase products definition that the sample
* app will use. The product definition includes two properties: "SKU" and
* "Available Marketplace".
*
*/
public enum MySku {
//The only subscription product used in this sample app
MY_MAGAZINE_SUBS("com.amazon.sample.iap.subscription.mymagazine", "US"),
MY_MAGAZINE_SUBS_MONTH("com.amazon.sample.iap.subscription.mymagazine.month", "US"),
MY_MAGAZINE_SUBS_QUARTER("com.amazon.sample.iap.subscription.mymagazine.quarter", "US");
private final String sku;
private final String availableMarkpetplace;
/**
* Returns the Sku string of the MySku object
* #return
*/
public String getSku() {
return this.sku;
}
/**
* Returns the Available Marketplace of the MySku object
* #return
*/
public String getAvailableMarketplace() {
return this.availableMarkpetplace;
}
private MySku(final String sku, final String availableMarkpetplace) {
this.sku = sku;
this.availableMarkpetplace = availableMarkpetplace;
}
/**
* Returns the MySku object from the specified Sku and marketplace value.
* #param sku
* #param marketplace
* #return
*/
public static MySku fromSku(final String sku, final String marketplace) {
/* if (MY_MAGAZINE_SUBS.getSku().equals(sku) && (null == marketplace || MY_MAGAZINE_SUBS.getAvailableMarketplace()
.equals(marketplace))) {
return MY_MAGAZINE_SUBS;
}*/
return MY_MAGAZINE_SUBS.getSku().equals(sku) && (null == marketplace || MY_MAGAZINE_SUBS.getAvailableMarketplace()
.equals(marketplace)) ? MY_MAGAZINE_SUBS :
(MY_MAGAZINE_SUBS_MONTH.getSku().equals(sku) && (marketplace == null || MY_MAGAZINE_SUBS_MONTH.getAvailableMarketplace().equals(marketplace)))
? MY_MAGAZINE_SUBS_MONTH : (MY_MAGAZINE_SUBS_QUARTER.getSku().equals(sku) && (marketplace == null || MY_MAGAZINE_SUBS_QUARTER.getAvailableMarketplace().equals(marketplace))) ? MY_MAGAZINE_SUBS_QUARTER : null;
}
}
Build.gradle code -
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.example.sampleiapus"
minSdkVersion 15
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation files('libs/in-app-purchasing-2.0.76.jar')
}
Proguard file -
-dontwarn com.amazon.**
-keep class com.amazon.** {*;}
-keepattributes *Annotation*
-optimizations !code/allocation/variable
If proguard file does not contain -optimizations !code/allocation/variable
then when i click on purchase button then it shows me an error dialog.
and if i am putting the line -optimizations !code/allocation/variable then i am not getting onPurchase event. Please help me in it. i am stuck since last 5 days in it. Thanks in advance
Did you submit the IAP items on Amazon developer console? Their status should be "LIVE", otherwise your app cannot retrieve them at runtime. I suspect that's what caused the error message.
If that's not the problem, checking logcat should help identify the root cause.
Related
I'm developing a workspace add-on with alternate runtime; I configured the add-on to work with spreadsheets and I need to retrieve the spreadsheet id when the user opens the add-on. For test purposes I created a cloud function that contains the business logic.
My deployment.json file is the following:
{
"oauthScopes": ["https://www.googleapis.com/auth/spreadsheets.currentonly", "https://www.googleapis.com/auth/drive.file"],
"addOns": {
"common": {
"name": "My Spreadsheet Add-on",
"logoUrl": "https://cdn.icon-icons.com/icons2/2070/PNG/512/penguin_icon_126624.png"
},
"sheets": {
"homepageTrigger": {
"runFunction": "cloudFunctionUrl"
}
}
}
}
However, the request I receive seems to be empty and without the id of the spreadsheet in which I am, while I was expecting to have the spreadsheet id as per documentation
Is there anything else I need to configure?
The relevant code is quite easy, I'm just printing the request:
exports.getSpreadsheetId = function addonsHomePage (req, res) { console.log('called', req.method); console.log('body', req.body); res.send(createAction()); };
the information showed in the log is:
sheets: {}
Thank you
UPDATE It's a known issue of the engineering team, here you can find the ticket
The information around Workspace Add-ons is pretty new and the documentation is pretty sparse.
In case anyone else comes across this issue ... I solved it in python using CloudRun by creating a button that checks for for the object then if there is no object it requests access to the sheet in question.
from flask import Flask
from flask import request
app = Flask(__name__)
#app.route('/', methods=['POST'])
def test_addon_homepage():
req_body = request.get_json()
sheet_info = req_body.get('sheets')
card = {
"action": {
"navigations": [
{
"pushCard": {
"sections": [
{
"widgets": [
{
"textParagraph": {
"text": f"Hello {sheet_info.get('title','Auth Needed')}!"
}
}
]
}
]
}
}
]
}
}
if not sheet_info:
card = create_file_auth_button(card)
return card
def create_file_auth_button(self, card):
card['action']['navigations'][0]['pushCard']['fixedFooter'] = {
'primaryButton': {
'text': 'Authorize file access',
'onClick': {
'action': {
'function': 'https://example-cloudrun.a.run.app/authorize_sheet'
}
}
}
}
return card
#app.route('/authorize_sheet', methods=['POST'])
def authorize_sheet():
payload = {
'renderActions': {
'hostAppAction': {
'editorAction': {
'requestFileScopeForActiveDocument': {}
}
}
}
}
return payload
I can't mint token using ERC20PresetMinterPauserUpgradeable.
i don't understand what's going on here, I'm trying to deploy a sort of simple ICO where I have a token contract, ERC20PresetMinterPauserUpgradeable Paddy. I try to deploy it from a second contract which will be granted the role MINTER, IcoSeller.
the error I get from remix is:
call to IcoSeller.getTokenNameFromPaddy errored: Error: Internal
JSON-RPC error. { "message": "VM Exception while processing
transaction: revert", "code": -32000, "data": {
"0x04c0f0d7e658c964b706f47d7263bb9e291fd02ada2a683259efc397bde4aac3":
{ "error": "revert", "program_counter": 511, "return": "0x" },
"stack": "c: VM Exception while processing transaction: revert\n at
Function.c.fromResults
(/Users/fabri/.nvm/versions/node/v10.24.0/lib/node_modules/ganache-cli/build/ganache-core.node.cli.js:4:192416)\n
at readyCall
(/Users/fabri/.nvm/versions/node/v10.24.0/lib/node_modules/ganache-cli/build/ganache-core.node.cli.js:42:50402)",
"name": "c" } }
I think I'm missing something here but I can't really understand what.
I am able to compile and deploy everything.
PADDY:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "#openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "#openzeppelin/contracts-upgradeable/token/ERC20/presets/ERC20PresetMinterPauserUpgradeable.sol";
/**
* #title PadelCoin
* #dev it is the coin itself. here I specify the name and the simbol
*
*/
contract Paddy is Initializable, ERC20PresetMinterPauserUpgradeable {
function initializePaddy(string memory _name, string memory _symbol) public initializer{
//create token and gives admin, minter, pauser to who deploys the contract
ERC20PresetMinterPauserUpgradeable.initialize(_name, _symbol);
}
}
I can't even get the tokenName from IcoSeller contract.
IcoSeller:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "#openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "#openzeppelin/contracts-upgradeable/token/ERC20/presets/ERC20PresetMinterPauserUpgradeable.sol";
import "./Paddy.sol";
/**
* #dev //initializes paddy and gives this contract minter, pauser and admin role
**/
contract IcoSeller is Initializable {
ERC20PresetMinterPauserUpgradeable paddy;
function initializeIcoDeployer() public initializer{
paddy.initialize("PaddyCoin", "PADDY");
}
/**
* #dev emits Transfer
**/
function sellToPublic(address _to, uint _amount) public{
paddy.mint(_to, _amount);
}
function getTokenNameFromPaddy() public view
returns(string memory name){
return paddy.name();
}
}
here is the migration script:
const { deployProxy,upgradeProxy } = require('#openzeppelin/truffle-upgrades');
const IcoSeller = artifacts.require('IcoSeller');
module.exports = async function (deployer) {
const ico = await deployProxy(IcoSeller, { deployer });
const icoUpgraded = await upgradeProxy(ico.address, IcoSeller, { deployer });
console.log('Ico Deployed at address: ', ico.address);
console.log('Ico Upgraded at address: ', icoUpgraded.address);
};
I'm trying to get file uploads to work in my Laravel Nova on a Vapor server.
When I try to upload, it keeps showing me a 401 response on /vapor/signed-storage-url.
What am I missing?
This is my Nova Resource:
public function fields(Request $request)
{
return [
VaporFile::make('Attachment')->rules('bail', 'required', function ($attribute, $value, $fail) use ($request) {
if (Storage::size($request->input('vaporFile')[$attribute]['key']) > 1000000) {
return $fail('The document size may not be greater than 1 MB');
}
}),
This is added to my app.js:
window.Vapor = require("laravel-vapor");
This is my registered policy:
class UserPolicy
{
use HandlesAuthorization;
/**
* Determine whether the user can upload files.
*
* #param \App\User $user
* #return mixed
*/
public function uploadFiles(User $user)
{
return true;
}
Looks to me I've done everything correctly.. but it still fails.
I'm looking to set up smart commits in JIRA, but my developers want to know all the options for their transitions. In order to help them, I'd like to print a cheat-sheet of all transition names (I trust they are smart enough to figure out what does what from there).
But when I look through the REST API documentation, I can only find a way to get the list of transitions for a particular issue (presumably via its status). Is there a way to get the list of all transitions that any ticket can take at any point in its workflow?
You can list the transitions of a given ticket via this endpoint:
/rest/api/2/issue/${issueIdOrKey}/transitions
For a more in depth explanation take a look here:
Does the JIRA REST API require submitting a transition ID when transitioning an issue?
You can get all transitions for project with /rest/api/2/project/{projectIdOrKey}/statuses endpoint. Here is response example, look at "statuses" array:
[
{
"self": "http://localhost:8090/jira/rest/api/2.0/issueType/3",
"id": "3",
"name": "Task",
"subtask": false,
"statuses": [
{
"self": "http://localhost:8090/jira/rest/api/2.0/status/10000",
"description": "The issue is currently being worked on.",
"iconUrl": "http://localhost:8090/jira/images/icons/progress.gif",
"name": "In Progress",
"id": "10000"
},
{
"self": "http://localhost:8090/jira/rest/api/2.0/status/5",
"description": "The issue is closed.",
"iconUrl": "http://localhost:8090/jira/images/icons/closed.gif",
"name": "Closed",
"id": "5"
}
]
}
]
But it doesn't give you exactly list of transitions that any issue can take at any time, and I'm not sure that such method exist in API.
public void changeStatus(IssueRestClient iRestClient,
List<Statuses> JiraStatuses, String key) {
String status = "To Do";
for (Statuses statuses : vOneToJiraStatuses) {
if (1 == statuses.compareTo(status)) {
try {
String _transition = statuses.getTransition();
Issue issue = iRestClient.getIssue(key).get();
Transition transition = getTransition(iRestClient, issue,
_transition);
if (!(isBlankOrNull(transition))) {
if (!(issue.getStatus().getName()
.equalsIgnoreCase(_transition)))
transition(transition, issue, null, iRestClient,
status);
}
} catch (Exception e) {
Constants.ERROR.info(Level.INFO, e);
}
break;
}
}
}
List is a pojo implementation where statuses and transitions defined in xml are injected through setter/constructor.
private void transition(Transition transition, Issue issue,
FieldInput fieldInput, IssueRestClient issueRestClient,
String status) throws Exception {
if (isBlankOrNull(fieldInput)) {
TransitionInput transitionInput = new TransitionInput(
transition.getId());
issueRestClient.transition(issue, transitionInput).claim();
Constants.REPORT.info("Status Updated for : " + issue.getKey());
} else {
TransitionInput transitionInput = new TransitionInput(
transition.getId());
issueRestClient.transition(issue, transitionInput).claim();
Constants.REPORT.info("Status Updated for : " + issue.getKey());
}
}
public Transition getTransition(IssueRestClient issueRestClient,
Issue issue, String _transition) {
Promise<Iterable<Transition>> ptransitions = issueRestClient
.getTransitions(issue);
Iterable<Transition> transitions = ptransitions.claim();
for (Transition transition : transitions) {
if (transition.getName().equalsIgnoreCase(_transition)) {
return transition;
}
}
return null;
}
In Short using Transition API of JIRA we can fetch all the transitions to set statuses
I want to integrate In app billing in my android app. I am using version 3 apis. So for this I have created one managed product.
I am following this tutorial. Given below is my code.
IabHelper mHelper;
final String BONUS_BUDGET = "bonus_budget";
Button purchaseButton;
String applePrice, skuID;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fantasy_login);
purchaseButton = (Button) findViewById(R.id.login_button);
String base64EncodedPublicKey = "MY BASE64 KEY";
MyLog.e(TAG, "onCreate");
mHelper = new IabHelper(this, base64EncodedPublicKey);
final IabHelper.QueryInventoryFinishedListener mQueryFinishedListener = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result,
Inventory inventory) {
if (result.isFailure()) {
// handle error
return;
} else {
Log.e(TAG,
"result : " + result.getResponse()
+ result.getMessage());
}
try {
if (inventory == null) {
Toast.makeText(FC_FantasyCricketLoginActivity.this,
"Inventory is null", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(
FC_FantasyCricketLoginActivity.this,
inventory.getSkuDetails(BONUS_BUDGET)
.getPrice().toString(),
Toast.LENGTH_LONG).show();
}
} catch (Exception e) {
Toast.makeText(FC_FantasyCricketLoginActivity.this,
"inventory catch block", Toast.LENGTH_LONG).show();
}
// Toast.makeText(FC_FantasyCricketLoginActivity.this, "",
// duration)
// Log.e(TAG,
// "Inventory :" + inventory.getSkuDetails(BONUS_BUDGET).);
//
// applePrice =
// inventory.getSkuDetails(BONUS_BUDGET).getPrice();
// skuID = inventory.getSkuDetails(BONUS_BUDGET).getSku();
// update the UI
}
};
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
#Override
public void onIabSetupFinished(IabResult result) {
if (result.isSuccess()) {
Log.e(TAG, "Successfully set up in app billing");
List<String> additionalSkuList = new ArrayList<String>();
additionalSkuList.add(BONUS_BUDGET);
Log.e(TAG, "Size of list"
+ additionalSkuList.get(0).toString());
mHelper.queryInventoryAsync(true, additionalSkuList,
mQueryFinishedListener);
} else {
Log.e(TAG,
"Problem in setting of in app billing "
+ result.toString());
}
}
});
final IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result,
Purchase purchase) {
if (result.isFailure()) {
Log.d(TAG, "Error purchasing: " + result);
return;
} else if (purchase.getSku().equals(skuID)) {
Log.e(TAG,
"Purchase done time:"
+ String.valueOf(purchase.getPurchaseTime())
+ "SKU id : " + purchase.getSku());
}
}
};
purchaseButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
mHelper.launchPurchaseFlow(FC_FantasyCricketLoginActivity.this,
skuID, 10001, mPurchaseFinishedListener,
"bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ");
}
});
}
It displays product and it's displaying that it's in test mode. But after that it displays Payment Options. Do I need to add my actual account this or is there a way to test without adding an actual account ?
You need a "real" account to test in app-billing on Android.
This account must be different than the account you use for the developer console.
You will have to enter valid credit card information.
Then add this account to account with testing access. (Developer console -> Settings -> Account Details -> Gmail accounts with testing access)
When you use a account to purchase items, the account is billed through Google Checkout and your Google Checkout Merchant account receives a payout for the purchase. Therefore, you may want to refund purchases that are made with that account (go to your Google Checkout, select order you want to refund and click Cancel entire order), otherwise the purchases will show up as actual payouts to your merchant account.
Quote from Google website:
Test purchases are real orders and Google Play processes them in the
same way as other orders. When purchases are complete, Google Play
prevents the orders from going to financial processing, ensuring that
there are no actual charges to user accounts, and automatically
canceling the completed orders after 14 days.
Link: http://developer.android.com/google/play/billing/billing_testing.html