| @@ -227,11 +227,20 @@ public: | |||||
| props.add (new BooleanPropertyComponent (getMicrophonePermissionValue(), "Microphone access", "Enabled"), | props.add (new BooleanPropertyComponent (getMicrophonePermissionValue(), "Microphone access", "Enabled"), | ||||
| "Enable this to allow your app to use the microphone. " | "Enable this to allow your app to use the microphone. " | ||||
| "The user of your app will be prompted to grant microphone access permissions."); | "The user of your app will be prompted to grant microphone access permissions."); | ||||
| } | |||||
| else if (projectType.isGUIApplication()) | |||||
| { | |||||
| props.add (new TextPropertyComponent (getSetting ("documentExtensions"), "Document file extensions", 128, false), | |||||
| "A comma-separated list of file extensions for documents that your app can open. " | |||||
| "Using a leading '.' is optional, and the extensions are not case-sensitive."); | |||||
| } | |||||
| props.add (new BooleanPropertyComponent (getInAppPurchasesValue(), "In-App purchases capability", "Enabled"), | |||||
| "Enable this to grant your app the capability for in-app purchases. " | |||||
| "This option requires that you specify a valid Development Team ID."); | |||||
| props.add (new BooleanPropertyComponent (getInAppPurchasesValue(), "In-App purchases capability", "Enabled"), | |||||
| "Enable this to grant your app the capability for in-app purchases. " | |||||
| "This option requires that you specify a valid Development Team ID."); | |||||
| if (iOS) | |||||
| { | |||||
| props.add (new BooleanPropertyComponent (getBackgroundAudioValue(), "Audio background capability", "Enabled"), | props.add (new BooleanPropertyComponent (getBackgroundAudioValue(), "Audio background capability", "Enabled"), | ||||
| "Enable this to grant your app the capability to access audio when in background mode."); | "Enable this to grant your app the capability to access audio when in background mode."); | ||||
| @@ -244,12 +253,6 @@ public: | |||||
| props.add (new BooleanPropertyComponent (getAppGroupsEnabledValue(), "App groups capability", "Enabled"), | props.add (new BooleanPropertyComponent (getAppGroupsEnabledValue(), "App groups capability", "Enabled"), | ||||
| "Enable this to grant your app the capability to share resources between apps using the same app group ID."); | "Enable this to grant your app the capability to share resources between apps using the same app group ID."); | ||||
| } | } | ||||
| else if (projectType.isGUIApplication()) | |||||
| { | |||||
| props.add (new TextPropertyComponent (getSetting ("documentExtensions"), "Document file extensions", 128, false), | |||||
| "A comma-separated list of file extensions for documents that your app can open. " | |||||
| "Using a leading '.' is optional, and the extensions are not case-sensitive."); | |||||
| } | |||||
| props.add (new TextPropertyComponent (getPListToMergeValue(), "Custom PList", 8192, true), | props.add (new TextPropertyComponent (getPListToMergeValue(), "Custom PList", 8192, true), | ||||
| "You can paste the contents of an XML PList file in here, and the settings that it contains will override any " | "You can paste the contents of an XML PList file in here, and the settings that it contains will override any " | ||||
| @@ -783,7 +786,7 @@ public: | |||||
| attributes << "DevelopmentTeam = " << developmentTeamID << "; "; | attributes << "DevelopmentTeam = " << developmentTeamID << "; "; | ||||
| auto appGroupsEnabled = (owner.iOS && owner.isAppGroupsEnabled() ? 1 : 0); | auto appGroupsEnabled = (owner.iOS && owner.isAppGroupsEnabled() ? 1 : 0); | ||||
| auto inAppPurchasesEnabled = (owner.iOS && owner.isInAppPurchasesEnabled()) ? 1 : 0; | |||||
| auto inAppPurchasesEnabled = owner.isInAppPurchasesEnabled() ? 1 : 0; | |||||
| auto interAppAudioEnabled = (owner.iOS | auto interAppAudioEnabled = (owner.iOS | ||||
| && type == Target::StandalonePlugIn | && type == Target::StandalonePlugIn | ||||
| && owner.getProject().shouldEnableIAA()) ? 1 : 0; | && owner.getProject().shouldEnableIAA()) ? 1 : 0; | ||||
| @@ -1059,7 +1062,7 @@ public: | |||||
| s.add ("SEPARATE_STRIP = YES"); | s.add ("SEPARATE_STRIP = YES"); | ||||
| } | } | ||||
| if (owner.iOS && owner.isInAppPurchasesEnabled()) | |||||
| if (owner.isInAppPurchasesEnabled()) | |||||
| defines.set ("JUCE_IN_APP_PURCHASES", "1"); | defines.set ("JUCE_IN_APP_PURCHASES", "1"); | ||||
| defines = mergePreprocessorDefs (defines, owner.getAllPreprocessorDefs (config, type)); | defines = mergePreprocessorDefs (defines, owner.getAllPreprocessorDefs (config, type)); | ||||
| @@ -2146,7 +2149,7 @@ private: | |||||
| { | { | ||||
| if (! projectType.isStaticLibrary()) | if (! projectType.isStaticLibrary()) | ||||
| { | { | ||||
| if (iOS && isInAppPurchasesEnabled()) | |||||
| if (isInAppPurchasesEnabled()) | |||||
| xcodeFrameworks.addIfNotAlreadyThere ("StoreKit"); | xcodeFrameworks.addIfNotAlreadyThere ("StoreKit"); | ||||
| xcodeFrameworks.addTokens (getExtraFrameworksString(), ",;", "\"'"); | xcodeFrameworks.addTokens (getExtraFrameworksString(), ",;", "\"'"); | ||||
| @@ -28,7 +28,7 @@ namespace juce | |||||
| { | { | ||||
| InAppPurchases::InAppPurchases() | InAppPurchases::InAppPurchases() | ||||
| #if JUCE_ANDROID || JUCE_IOS | |||||
| #if JUCE_ANDROID || JUCE_IOS || JUCE_MAC | |||||
| : pimpl (new Pimpl (*this)) | : pimpl (new Pimpl (*this)) | ||||
| #endif | #endif | ||||
| {} | {} | ||||
| @@ -37,7 +37,7 @@ InAppPurchases::~InAppPurchases() {} | |||||
| bool InAppPurchases::isInAppPurchasesSupported() const | bool InAppPurchases::isInAppPurchasesSupported() const | ||||
| { | { | ||||
| #if JUCE_ANDROID || JUCE_IOS | |||||
| #if JUCE_ANDROID || JUCE_IOS || JUCE_MAC | |||||
| return pimpl->isInAppPurchasesSupported(); | return pimpl->isInAppPurchasesSupported(); | ||||
| #else | #else | ||||
| return false; | return false; | ||||
| @@ -46,7 +46,7 @@ bool InAppPurchases::isInAppPurchasesSupported() const | |||||
| void InAppPurchases::getProductsInformation (const StringArray& productIdentifiers) | void InAppPurchases::getProductsInformation (const StringArray& productIdentifiers) | ||||
| { | { | ||||
| #if JUCE_ANDROID || JUCE_IOS | |||||
| #if JUCE_ANDROID || JUCE_IOS || JUCE_MAC | |||||
| pimpl->getProductsInformation (productIdentifiers); | pimpl->getProductsInformation (productIdentifiers); | ||||
| #else | #else | ||||
| Array<Product> products; | Array<Product> products; | ||||
| @@ -62,7 +62,7 @@ void InAppPurchases::purchaseProduct (const String& productIdentifier, | |||||
| const StringArray& upgradeProductIdentifiers, | const StringArray& upgradeProductIdentifiers, | ||||
| bool creditForUnusedSubscription) | bool creditForUnusedSubscription) | ||||
| { | { | ||||
| #if JUCE_ANDROID || JUCE_IOS | |||||
| #if JUCE_ANDROID || JUCE_IOS || JUCE_MAC | |||||
| pimpl->purchaseProduct (productIdentifier, isSubscription, | pimpl->purchaseProduct (productIdentifier, isSubscription, | ||||
| upgradeProductIdentifiers, creditForUnusedSubscription); | upgradeProductIdentifiers, creditForUnusedSubscription); | ||||
| #else | #else | ||||
| @@ -75,7 +75,7 @@ void InAppPurchases::purchaseProduct (const String& productIdentifier, | |||||
| void InAppPurchases::restoreProductsBoughtList (bool includeDownloadInfo, const String& subscriptionsSharedSecret) | void InAppPurchases::restoreProductsBoughtList (bool includeDownloadInfo, const String& subscriptionsSharedSecret) | ||||
| { | { | ||||
| #if JUCE_ANDROID || JUCE_IOS | |||||
| #if JUCE_ANDROID || JUCE_IOS || JUCE_MAC | |||||
| pimpl->restoreProductsBoughtList (includeDownloadInfo, subscriptionsSharedSecret); | pimpl->restoreProductsBoughtList (includeDownloadInfo, subscriptionsSharedSecret); | ||||
| #else | #else | ||||
| listeners.call (&Listener::purchasesListRestored, Array<Listener::PurchaseInfo>(), false, "In-app purchases unavailable"); | listeners.call (&Listener::purchasesListRestored, Array<Listener::PurchaseInfo>(), false, "In-app purchases unavailable"); | ||||
| @@ -85,7 +85,7 @@ void InAppPurchases::restoreProductsBoughtList (bool includeDownloadInfo, const | |||||
| void InAppPurchases::consumePurchase (const String& productIdentifier, const String& purchaseToken) | void InAppPurchases::consumePurchase (const String& productIdentifier, const String& purchaseToken) | ||||
| { | { | ||||
| #if JUCE_ANDROID || JUCE_IOS | |||||
| #if JUCE_ANDROID || JUCE_IOS || JUCE_MAC | |||||
| pimpl->consumePurchase (productIdentifier, purchaseToken); | pimpl->consumePurchase (productIdentifier, purchaseToken); | ||||
| #else | #else | ||||
| listeners.call (&Listener::productConsumed, productIdentifier, false, "In-app purchases unavailable"); | listeners.call (&Listener::productConsumed, productIdentifier, false, "In-app purchases unavailable"); | ||||
| @@ -98,7 +98,7 @@ void InAppPurchases::removeListener (Listener* l) { listeners.remove (l); } | |||||
| void InAppPurchases::startDownloads (const Array<Download*>& downloads) | void InAppPurchases::startDownloads (const Array<Download*>& downloads) | ||||
| { | { | ||||
| #if JUCE_ANDROID || JUCE_IOS | |||||
| #if JUCE_ANDROID || JUCE_IOS || JUCE_MAC | |||||
| pimpl->startDownloads (downloads); | pimpl->startDownloads (downloads); | ||||
| #else | #else | ||||
| ignoreUnused (downloads); | ignoreUnused (downloads); | ||||
| @@ -107,7 +107,7 @@ void InAppPurchases::startDownloads (const Array<Download*>& downloads) | |||||
| void InAppPurchases::pauseDownloads (const Array<Download*>& downloads) | void InAppPurchases::pauseDownloads (const Array<Download*>& downloads) | ||||
| { | { | ||||
| #if JUCE_ANDROID || JUCE_IOS | |||||
| #if JUCE_ANDROID || JUCE_IOS || JUCE_MAC | |||||
| pimpl->pauseDownloads (downloads); | pimpl->pauseDownloads (downloads); | ||||
| #else | #else | ||||
| ignoreUnused (downloads); | ignoreUnused (downloads); | ||||
| @@ -116,7 +116,7 @@ void InAppPurchases::pauseDownloads (const Array<Download*>& downloads) | |||||
| void InAppPurchases::resumeDownloads (const Array<Download*>& downloads) | void InAppPurchases::resumeDownloads (const Array<Download*>& downloads) | ||||
| { | { | ||||
| #if JUCE_ANDROID || JUCE_IOS | |||||
| #if JUCE_ANDROID || JUCE_IOS || JUCE_MAC | |||||
| pimpl->resumeDownloads (downloads); | pimpl->resumeDownloads (downloads); | ||||
| #else | #else | ||||
| ignoreUnused (downloads); | ignoreUnused (downloads); | ||||
| @@ -125,7 +125,7 @@ void InAppPurchases::resumeDownloads (const Array<Download*>& downloads) | |||||
| void InAppPurchases::cancelDownloads (const Array<Download*>& downloads) | void InAppPurchases::cancelDownloads (const Array<Download*>& downloads) | ||||
| { | { | ||||
| #if JUCE_ANDROID || JUCE_IOS | |||||
| #if JUCE_ANDROID || JUCE_IOS || JUCE_MAC | |||||
| pimpl->cancelDownloads (downloads); | pimpl->cancelDownloads (downloads); | ||||
| #else | #else | ||||
| ignoreUnused (downloads); | ignoreUnused (downloads); | ||||
| @@ -267,7 +267,7 @@ private: | |||||
| friend void juce_inAppPurchaseCompleted (void*); | friend void juce_inAppPurchaseCompleted (void*); | ||||
| #endif | #endif | ||||
| #if JUCE_ANDROID || JUCE_IOS | |||||
| #if JUCE_ANDROID || JUCE_IOS || JUCE_MAC | |||||
| struct Pimpl; | struct Pimpl; | ||||
| friend struct Pimpl; | friend struct Pimpl; | ||||
| @@ -51,8 +51,8 @@ | |||||
| #if JUCE_IN_APP_PURCHASES | #if JUCE_IN_APP_PURCHASES | ||||
| #if JUCE_ANDROID | #if JUCE_ANDROID | ||||
| #include "native/juce_android_InAppPurchases.cpp" | #include "native/juce_android_InAppPurchases.cpp" | ||||
| #elif JUCE_IOS | |||||
| #include "native/juce_ios_InAppPurchases.cpp" | |||||
| #elif JUCE_IOS || JUCE_MAC | |||||
| #include "native/juce_ios_InAppPurchases.cpp" | |||||
| #endif | #endif | ||||
| #include "in_app_purchases/juce_InAppPurchases.cpp" | #include "in_app_purchases/juce_InAppPurchases.cpp" | ||||
| @@ -100,9 +100,15 @@ struct InAppPurchases::Pimpl : public SKDelegateAndPaymentObserver | |||||
| DownloadImpl (SKDownload* downloadToUse) : download (downloadToUse) {} | DownloadImpl (SKDownload* downloadToUse) : download (downloadToUse) {} | ||||
| String getProductId() const override { return nsStringToJuce (download.contentIdentifier); } | String getProductId() const override { return nsStringToJuce (download.contentIdentifier); } | ||||
| int64 getContentLength() const override { return download.contentLength; } | |||||
| String getContentVersion() const override { return nsStringToJuce (download.contentVersion); } | String getContentVersion() const override { return nsStringToJuce (download.contentVersion); } | ||||
| #if JUCE_IOS | |||||
| int64 getContentLength() const override { return download.contentLength; } | |||||
| Status getStatus() const override { return SKDownloadStateToDownloadStatus (download.downloadState); } | Status getStatus() const override { return SKDownloadStateToDownloadStatus (download.downloadState); } | ||||
| #else | |||||
| int64 getContentLength() const override { return [download.contentLength longLongValue]; } | |||||
| Status getStatus() const override { return SKDownloadStateToDownloadStatus (download.state); } | |||||
| #endif | |||||
| SKDownload* download; | SKDownload* download; | ||||
| }; | }; | ||||
| @@ -146,9 +152,14 @@ struct InAppPurchases::Pimpl : public SKDelegateAndPaymentObserver | |||||
| { | { | ||||
| for (SKDownload* d in transaction.downloads) | for (SKDownload* d in transaction.downloads) | ||||
| { | { | ||||
| if (d.downloadState != SKDownloadStateFinished | |||||
| && d.downloadState != SKDownloadStateFailed | |||||
| && d.downloadState != SKDownloadStateCancelled) | |||||
| #if JUCE_IOS | |||||
| SKDownloadState state = d.downloadState; | |||||
| #else | |||||
| SKDownloadState state = d.state; | |||||
| #endif | |||||
| if (state != SKDownloadStateFinished | |||||
| && state != SKDownloadStateFailed | |||||
| && state != SKDownloadStateCancelled) | |||||
| { | { | ||||
| return false; | return false; | ||||
| } | } | ||||
| @@ -308,7 +319,11 @@ struct InAppPurchases::Pimpl : public SKDelegateAndPaymentObserver | |||||
| { | { | ||||
| if (auto* pendingDownload = getPendingDownloadFor (download)) | if (auto* pendingDownload = getPendingDownloadFor (download)) | ||||
| { | { | ||||
| #if JUCE_IOS | |||||
| switch (download.downloadState) | switch (download.downloadState) | ||||
| #else | |||||
| switch (download.state) | |||||
| #endif | |||||
| { | { | ||||
| case SKDownloadStateWaiting: break; | case SKDownloadStateWaiting: break; | ||||
| case SKDownloadStatePaused: owner.listeners.call (&Listener::productDownloadPaused, *pendingDownload); break; | case SKDownloadStatePaused: owner.listeners.call (&Listener::productDownloadPaused, *pendingDownload); break; | ||||
| @@ -467,7 +482,13 @@ struct InAppPurchases::Pimpl : public SKDelegateAndPaymentObserver | |||||
| { | { | ||||
| if (auto* pdt = getPendingDownloadsTransactionSKDownloadFor (download)) | if (auto* pdt = getPendingDownloadsTransactionSKDownloadFor (download)) | ||||
| { | { | ||||
| auto contentURL = download.downloadState == SKDownloadStateFinished | |||||
| #if JUCE_IOS | |||||
| SKDownloadState state = download.downloadState; | |||||
| #else | |||||
| SKDownloadState state = download.state; | |||||
| #endif | |||||
| auto contentURL = state == SKDownloadStateFinished | |||||
| ? URL (nsStringToJuce (download.contentURL.absoluteString)) | ? URL (nsStringToJuce (download.contentURL.absoluteString)) | ||||
| : URL(); | : URL(); | ||||