Skip to content

Commit

Permalink
Add Android In-App Review
Browse files Browse the repository at this point in the history
Also add macOS :)
  • Loading branch information
jamesmontemagno committed Sep 22, 2020
1 parent f6c63c6 commit 1d96d75
Show file tree
Hide file tree
Showing 98 changed files with 15,724 additions and 50 deletions.
24 changes: 16 additions & 8 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@ root = true

# Don't use tabs for indentation.
[*]
indent_style = tab
indent_style = space
# (Please don't specify an indent_size here; that has too many unintended consequences.)

# Code files
[*.{cs,csx,vb,vbx}]
indent_size = 4

# Code files
[*.sln]
indent_size = 4

# Xml project files
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
indent_size = 2
Expand All @@ -23,10 +27,14 @@ indent_size = 2
[*.json]
indent_size = 2

# XML files
[*.xml]
indent_size = 2

# Dotnet code style settings:
[*.{cs,vb}]
# Sort using and Import directives with System.* appearing first
dotnet_sort_system_directives_first = false
dotnet_sort_system_directives_first = true
# Avoid "this." and "Me." if not necessary
dotnet_style_qualification_for_field = false:suggestion
dotnet_style_qualification_for_property = false:suggestion
Expand All @@ -36,6 +44,7 @@ dotnet_style_qualification_for_event = false:suggestion
# Use language keywords instead of framework type names for type references
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
dotnet_style_predefined_type_for_member_access = true:suggestion
dotnet_style_require_accessibility_modifiers = omit_if_default:warning

# Suggest more modern language features when available
dotnet_style_object_initializer = true:suggestion
Expand All @@ -55,7 +64,7 @@ dotnet_naming_rule.methods_and_properties_must_be_pascal_case.symbols = method_a
dotnet_naming_rule.methods_and_properties_must_be_pascal_case.style = pascal_case_style

# Non-public members must be lower-case
dotnet_naming_symbols.non_public_symbols.applicable_kinds = property,method,field,event,delegate
dotnet_naming_symbols.non_public_symbols.applicable_kinds = field
dotnet_naming_symbols.non_public_symbols.applicable_accessibilities = private
dotnet_naming_style.all_lower_case_style.capitalization = camel_case

Expand All @@ -72,13 +81,13 @@ csharp_style_var_elsewhere = true:error

# Prefer method-like constructs to have a block body
csharp_style_expression_bodied_methods = true:suggestion
csharp_style_expression_bodied_constructors = true:none
csharp_style_expression_bodied_operators = true:none
csharp_style_expression_bodied_constructors = true:suggestion
csharp_style_expression_bodied_operators = true:suggestion

# Prefer property-like constructs to have an expression-body
csharp_style_expression_bodied_properties = true:suggestion
csharp_style_expression_bodied_indexers = true:none
csharp_style_expression_bodied_accessors = true:none
csharp_style_expression_bodied_indexers = true:suggestion
csharp_style_expression_bodied_accessors = true:suggestion

# Suggest more modern language features when available
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
Expand All @@ -94,4 +103,3 @@ csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true

6 changes: 4 additions & 2 deletions src/StoreReview.Plugin/IStoreReview.shared.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace Plugin.StoreReview.Abstractions
using System.Threading.Tasks;

namespace Plugin.StoreReview.Abstractions
{
/// <summary>
/// Interface for StoreReview
Expand All @@ -20,6 +22,6 @@ public interface IStoreReview
/// <summary>
/// Requests an app review.
/// </summary>
void RequestReview();
Task RequestReview(bool testMode);
}
}
53 changes: 34 additions & 19 deletions src/StoreReview.Plugin/StoreReview.Plugin.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="MSBuild.Sdk.Extras/2.1.2">

<PropertyGroup>
<TargetFrameworks>netstandard1.0;netstandard2.0;MonoAndroid71;Xamarin.iOS10;uap10.0.15063;Xamarin.TVOS10;</TargetFrameworks>
<TargetFrameworks>netstandard1.0;netstandard2.0;MonoAndroid90;Xamarin.Mac20;Xamarin.iOS10;uap10.0.16299;Xamarin.TVOS10;</TargetFrameworks>
<AssemblyName>Plugin.StoreReview</AssemblyName>
<RootNamespace>Plugin.StoreReview</RootNamespace>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
Expand All @@ -22,26 +22,41 @@
<Description>
Easily request a review or open the store page for your app.
</Description>
<Copyright>Copyright 2018</Copyright>
<Copyright>Copyright 2020</Copyright>
<RepositoryUrl>https://github.com/jamesmontemagno/StoreReviewPlugin</RepositoryUrl>
<PackageReleaseNotes>See: https://github.com/jamesmontemagno/StoreReviewPlugin </PackageReleaseNotes>

<NeutralLanguage>en</NeutralLanguage>
<LangVersion>default</LangVersion>
<LangVersion>latest</LangVersion>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>


<GenerateDocumentationFile Condition=" '$(Configuration)' == 'Release' ">true</GenerateDocumentationFile>

<DebugType>full</DebugType>

<DefineConstants>$(DefineConstants);</DefineConstants>

<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>

<PropertyGroup Condition=" '$(Configuration)'=='Release' And '$(OS)' == 'Windows_NT' ">
<!-- sourcelink: Declare that the Repository URL can be published to NuSpec -->
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<!-- sourcelink: Embed source files that are not tracked by the source control manager to the PDB -->
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<!-- sourcelink: Include PDB in the built .nupkg -->
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
</PropertyGroup>
<ItemGroup Condition=" '$(Configuration)'=='Release' And '$(OS)' == 'Windows_NT' ">
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.0-beta-20204-02">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>

<PropertyGroup Condition=" '$(Configuration)'=='Debug' ">
<DebugSymbols>true</DebugSymbols>
<GenerateDocumentationFile>false</GenerateDocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)'=='Release' ">
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="MSBuild.Sdk.Extras" Version="1.4.0" PrivateAssets="All" />
<Compile Include="**\*.shared.cs" />
</ItemGroup>

Expand All @@ -50,12 +65,13 @@
</ItemGroup>

<ItemGroup Condition=" $(TargetFramework.StartsWith('uap10.0')) ">
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform" Version="5.2.4" />
<Compile Include="**\*.uwp.cs" />
</ItemGroup>

<ItemGroup Condition=" $(TargetFramework.StartsWith('MonoAndroid')) ">
<Compile Include="**\*.android.cs" />
<PackageReference Include="PlayCore" Version="1.8.0-rc" />
<PackageReference Include="Xamarin.Essentials" Version="1.5.3.2" />
</ItemGroup>

<ItemGroup Condition=" $(TargetFramework.StartsWith('Xamarin.iOS')) ">
Expand All @@ -66,9 +82,8 @@
<Compile Include="**\*.apple.cs" />
</ItemGroup>



<Import Project="$(MSBuildSDKExtrasTargets)" Condition="Exists('$(MSBuildSDKExtrasTargets)')" />


<ItemGroup Condition=" $(TargetFramework.StartsWith('Xamarin.Mac')) ">
<Compile Include="**\*.apple.cs" />
</ItemGroup>

</Project>
64 changes: 57 additions & 7 deletions src/StoreReview.Plugin/StoreReviewImplementation.android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,21 @@
using Android.Content;
using Android.OS;
using Android.Runtime;
using Com.Google.Android.Play.Core.Review;
using Com.Google.Android.Play.Core.Review.Testing;
using Com.Google.Android.Play.Core.Tasks;
using Plugin.StoreReview.Abstractions;
using System;
using System.Threading.Tasks;
using Task = System.Threading.Tasks.Task;

namespace Plugin.StoreReview
{
/// <summary>
/// Implementation for Feature
/// </summary>
[Preserve(AllMembers = true)]
public class StoreReviewImplementation : IStoreReview
public class StoreReviewImplementation : Java.Lang.Object, IStoreReview, IOnCompleteListener
{
/// <summary>
/// Opens the store listing.
Expand Down Expand Up @@ -69,11 +74,56 @@ public void OpenStoreReviewPage(string appId)
System.Diagnostics.Debug.WriteLine("Unable to launch app store: " + ex.Message);
}
}
/// <summary>
/// Requests an app review.
/// </summary>
public void RequestReview()
{

IReviewManager manager;
TaskCompletionSource<bool> tcs;
/// <summary>
/// Requests an app review.
/// </summary>
public async Task RequestReview(bool testMode)
{
tcs?.TrySetCanceled();
tcs = new TaskCompletionSource<bool>();

if (testMode)
manager = new FakeReviewManager(Application.Context);
else
manager = ReviewManagerFactory.Create(Application.Context);

forceReturn = false;
var request = manager.RequestReviewFlow();
request.AddOnCompleteListener(this);
await tcs.Task;
manager.Dispose();
request.Dispose();
}
}

Activity Activity =>
Xamarin.Essentials.Platform.CurrentActivity ?? throw new NullReferenceException("Current Activity is null, ensure that the MainActivity.cs file is configuring Xamarin.Essentials in your source code so the In App Billing can use it.");

bool forceReturn;
Com.Google.Android.Play.Core.Tasks.Task launchTask;
public void OnComplete(Com.Google.Android.Play.Core.Tasks.Task task)
{
if (!task.IsSuccessful || forceReturn)
{
tcs.TrySetResult(forceReturn);
launchTask?.Dispose();
return;
}

try
{
var reviewInfo = (ReviewInfo)task.GetResult(Java.Lang.Class.FromType(typeof(ReviewInfo)));
forceReturn = true;
launchTask = manager.LaunchReviewFlow(Activity, reviewInfo);
launchTask.AddOnCompleteListener(this);
}
catch (Exception ex)
{
tcs.TrySetResult(false);
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
}
}
54 changes: 44 additions & 10 deletions src/StoreReview.Plugin/StoreReviewImplementation.apple.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
using System;
using System.Diagnostics;
using System.Threading.Tasks;
#if !__MACOS__
using UIKit;
#endif
using StoreKit;

namespace Plugin.StoreReview
Expand All @@ -25,12 +27,18 @@ public void OpenStoreListing(string appId)
var url = $"itms-apps://itunes.apple.com/app/id{appId}";
#elif __TVOS__
var url = $"com.apple.TVAppStore://itunes.apple.com/app/id{appId}";
#elif __MACOS__
var url = $"macappstore://itunes.apple.com/app/id{appId}?mt=12";
#endif
try
{
UIApplication.SharedApplication.OpenUrl(new NSUrl(url));
}
catch (Exception ex)
#if __MACOS__
AppKit.NSWorkspace.SharedWorkspace.OpenUrl(new NSUrl(url));
#else
UIApplication.SharedApplication.OpenUrl(new NSUrl(url));
#endif
}
catch (Exception ex)
{
Debug.WriteLine("Unable to launch app store: " + ex.Message);
}
Expand All @@ -46,10 +54,16 @@ public void OpenStoreReviewPage(string appId)
var url = $"itms-apps://itunes.apple.com/app/id{appId}?action=write-review";
#elif __TVOS__
var url = $"com.apple.TVAppStore://itunes.apple.com/app/id{appId}?action=write-review";
#elif __MACOS__
var url = $"macappstore://itunes.apple.com/app/id{appId}?action=write-review";
#endif
try
{
UIApplication.SharedApplication.OpenUrl(new NSUrl(url));
#if __MACOS__
AppKit.NSWorkspace.SharedWorkspace.OpenUrl(new NSUrl(url));
#else
UIApplication.SharedApplication.OpenUrl(new NSUrl(url));
#endif
}
catch (Exception ex)
{
Expand All @@ -60,18 +74,38 @@ public void OpenStoreReviewPage(string appId)
/// <summary>
/// Requests an app review.
/// </summary>
public void RequestReview()
{
public Task RequestReview(bool testMode)
{
#if __IOS__
if (IsiOS103)
{
SKStoreReviewController.RequestReview();
}
#elif __MACOS__
using var info = new NSProcessInfo();
if (ParseVersion(info.OperatingSystemVersion.ToString()) >= new Version(10, 14))
{
SKStoreReviewController.RequestReview();
}
#endif
}

bool IsiOS103 => UIDevice.CurrentDevice.CheckSystemVersion(10, 3);

return Task.CompletedTask;
}

internal static Version ParseVersion(string version)
{
if (Version.TryParse(version, out var number))
return number;

if (int.TryParse(version, out var major))
return new Version(major, 0);

return new Version(0, 0);
}

#if __IOS__
bool IsiOS103 => UIDevice.CurrentDevice.CheckSystemVersion(10, 3);
#endif

}
}
}
4 changes: 2 additions & 2 deletions src/StoreReview.Plugin/StoreReviewImplementation.uwp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public void OpenStoreReviewPage(string appId) =>
/// <summary>
/// Requests an app review.
/// </summary>
public void RequestReview() => StoreRequestHelper.SendRequestAsync(StoreContext.GetDefault(), 16, string.Empty).WatchForError();
public async Task RequestReview(bool testMode) => _ = await StoreRequestHelper.SendRequestAsync(StoreContext.GetDefault(), 16, string.Empty).AsTask();

void OpenUrl(string url)
{
Expand All @@ -49,7 +49,7 @@ void OpenUrl(string url)
}
}

internal static partial class PlatformExtensions
static partial class PlatformExtensions
{
internal static void WatchForError(this IAsyncAction self) =>
self.AsTask().WatchForError();
Expand Down
Loading

0 comments on commit 1d96d75

Please sign in to comment.