diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj
index 6d44be7ddd6..315d54b7c60 100755
--- a/src/csharp/Grpc.Core/Grpc.Core.csproj
+++ b/src/csharp/Grpc.Core/Grpc.Core.csproj
@@ -46,8 +46,12 @@
runtimes/win/native/grpc_csharp_ext.x86.dll
true
-
- build/net45/
+
+ runtimes/monoandroid/armeabi-v7a/libgrpc_csharp_ext.so
+ true
+
+
+ runtimes/monoandroid/arm64-v8a/libgrpc_csharp_ext.so
true
@@ -69,4 +73,11 @@
+
+
+ true
+ build
+
+
+
diff --git a/src/csharp/Grpc.Core/GrpcEnvironment.cs b/src/csharp/Grpc.Core/GrpcEnvironment.cs
index 6bb2f6c3e54..27a91c723a4 100644
--- a/src/csharp/Grpc.Core/GrpcEnvironment.cs
+++ b/src/csharp/Grpc.Core/GrpcEnvironment.cs
@@ -423,7 +423,8 @@ namespace Grpc.Core
if (!hooksRegistered)
{
#if NETSTANDARD1_5
- System.Runtime.Loader.AssemblyLoadContext.Default.Unloading += (assemblyLoadContext) => { HandleShutdown(); };
+ // FIXME couldn't get around a "cannot resolve type" runtime exception on Xamarin.Android
+ //System.Runtime.Loader.AssemblyLoadContext.Default.Unloading += (assemblyLoadContext) => { HandleShutdown(); };
#else
AppDomain.CurrentDomain.ProcessExit += (sender, eventArgs) => { HandleShutdown(); };
AppDomain.CurrentDomain.DomainUnload += (sender, eventArgs) => { HandleShutdown(); };
diff --git a/src/csharp/Grpc.Core/Internal/NativeExtension.cs b/src/csharp/Grpc.Core/Internal/NativeExtension.cs
index d5ec998bbdb..5e1affcb996 100644
--- a/src/csharp/Grpc.Core/Internal/NativeExtension.cs
+++ b/src/csharp/Grpc.Core/Internal/NativeExtension.cs
@@ -106,7 +106,9 @@ namespace Grpc.Core.Internal
///
private static NativeMethods LoadNativeMethods()
{
- return PlatformApis.IsUnity ? LoadNativeMethodsUnity() : new NativeMethods(LoadUnmanagedLibrary());
+ return PlatformApis.IsUnity ? LoadNativeMethodsUnity() :
+ PlatformApis.IsXamarin ? LoadNativeMethodsXamarin() :
+ new NativeMethods(LoadUnmanagedLibrary());
}
///
@@ -128,6 +130,20 @@ namespace Grpc.Core.Internal
}
}
+ ///
+ /// Return native method delegates when running on the Xamarin platform.
+ /// WARNING: Xamarin support is experimental and work-in-progress. Don't expect it to work.
+ ///
+ private static NativeMethods LoadNativeMethodsXamarin()
+ {
+ if (PlatformApis.IsXamarinAndroid)
+ {
+ return new NativeMethods(new NativeMethods.DllImportsFromSharedLib());
+ }
+ // not tested yet
+ return new NativeMethods(new NativeMethods.DllImportsFromStaticLib());
+ }
+
private static string GetAssemblyPath()
{
var assembly = typeof(NativeExtension).GetTypeInfo().Assembly;
diff --git a/src/csharp/Grpc.Core/Internal/PlatformApis.cs b/src/csharp/Grpc.Core/Internal/PlatformApis.cs
index b90fbccb2bd..6c4ee0bdb79 100644
--- a/src/csharp/Grpc.Core/Internal/PlatformApis.cs
+++ b/src/csharp/Grpc.Core/Internal/PlatformApis.cs
@@ -33,12 +33,17 @@ namespace Grpc.Core.Internal
internal static class PlatformApis
{
const string UnityEngineApplicationClassName = "UnityEngine.Application, UnityEngine";
+ const string XamarinAndroidActivityClassName = "Android.App.Activity, Mono.Android";
+ const string XamariniOSEnumClassName = "Mono.CSharp.Enum, Mono.CSharp";
static readonly bool isLinux;
static readonly bool isMacOSX;
static readonly bool isWindows;
static readonly bool isMono;
static readonly bool isNetCore;
static readonly bool isUnity;
+ static readonly bool isXamarin;
+ static readonly bool isXamariniOS;
+ static readonly bool isXamarinAndroid;
static PlatformApis()
{
@@ -58,6 +63,9 @@ namespace Grpc.Core.Internal
#endif
isMono = Type.GetType("Mono.Runtime") != null;
isUnity = Type.GetType(UnityEngineApplicationClassName) != null;
+ isXamariniOS = Type.GetType(XamariniOSEnumClassName) != null;
+ isXamarinAndroid = Type.GetType(XamarinAndroidActivityClassName) != null;
+ isXamarin = isXamariniOS || isXamarinAndroid;
}
public static bool IsLinux
@@ -88,6 +96,31 @@ namespace Grpc.Core.Internal
get { return isUnity; }
}
+ ///
+ /// true if running on a Xamarin platform (either Xamarin.Android or Xamarin.iOS),
+ /// false otherwise.
+ ///
+ public static bool IsXamarin
+ {
+ get { return isXamarin; }
+ }
+
+ ///
+ /// true if running on Xamarin.iOS, false otherwise.
+ ///
+ public static bool IsXamariniOS
+ {
+ get { return isXamariniOS; }
+ }
+
+ ///
+ /// true if running on Xamarin.Android, false otherwise.
+ ///
+ public static bool IsXamarinAndroid
+ {
+ get { return isXamarinAndroid; }
+ }
+
///
/// true if running on .NET Core (CoreCLR), false otherwise.
///
diff --git a/src/csharp/Grpc.Core/Version.csproj.include b/src/csharp/Grpc.Core/Version.csproj.include
index 2b45e7ae203..cadf091e992 100755
--- a/src/csharp/Grpc.Core/Version.csproj.include
+++ b/src/csharp/Grpc.Core/Version.csproj.include
@@ -1,7 +1,7 @@
- 1.14.0-dev
+ 1.14.1-dev
3.5.1
diff --git a/src/csharp/Grpc.Core/build/MonoAndroid/Grpc.Core.targets b/src/csharp/Grpc.Core/build/MonoAndroid/Grpc.Core.targets
new file mode 100644
index 00000000000..f764f4cae1d
--- /dev/null
+++ b/src/csharp/Grpc.Core/build/MonoAndroid/Grpc.Core.targets
@@ -0,0 +1,21 @@
+
+
+
+ <_GrpcCoreNugetNativePath Condition="'$(_GrpcCoreNugetNativePath)' == ''">$(MSBuildThisFileDirectory)..\..\
+
+
+
+
+ Always
+ arm64-v8a
+
+
+
+
+
+ Always
+ armeabi-v7a
+
+
+
+
diff --git a/src/csharp/Grpc.Core/Grpc.Core.targets b/src/csharp/Grpc.Core/build/net45/Grpc.Core.targets
similarity index 100%
rename from src/csharp/Grpc.Core/Grpc.Core.targets
rename to src/csharp/Grpc.Core/build/net45/Grpc.Core.targets
diff --git a/src/csharp/experimental/build_native_ext_for_android.sh b/src/csharp/experimental/build_native_ext_for_android.sh
index 8197df7c536..4b4b26524fd 100755
--- a/src/csharp/experimental/build_native_ext_for_android.sh
+++ b/src/csharp/experimental/build_native_ext_for_android.sh
@@ -23,17 +23,28 @@ mkdir -p build
cd build
# set to the location where Android SDK is installed
-# e.g. ANDROID_NDK_PATH="$HOME/android-ndk-r16b"
+ANDROID_SDK_PATH="$HOME/Android/Sdk"
-cmake ../.. \
- -DCMAKE_SYSTEM_NAME=Android \
- -DCMAKE_SYSTEM_VERSION=15 \
- -DCMAKE_ANDROID_ARCH_ABI=armeabi-v7a \
+# set to location where Android NDK is installed, usually a subfolder of Android SDK
+# install the Android NDK through the Android SDK Manager
+ANDROID_NDK_PATH=${ANDROID_SDK_PATH}/ndk-bundle
+
+# set to location of the cmake executable
+# by default, use cmake binary from the Android SDK
+CMAKE_PATH="${ANDROID_SDK_PATH}/cmake/3.6.4111459/bin/cmake"
+
+# ANDROID_ABI in ('arm64-v8a', 'armeabi-v7a')
+${CMAKE_PATH} ../.. \
+ -DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK_PATH}/build/cmake/android.toolchain.cmake" \
-DCMAKE_ANDROID_NDK="${ANDROID_NDK_PATH}" \
-DCMAKE_ANDROID_STL_TYPE=c++_static \
-DRUN_HAVE_POSIX_REGEX=0 \
-DRUN_HAVE_STD_REGEX=0 \
-DRUN_HAVE_STEADY_CLOCK=0 \
- -DCMAKE_BUILD_TYPE=Release
+ -DCMAKE_BUILD_TYPE=Release \
+ -DANDROID_PLATFORM=android-28 \
+ -DANDROID_ABI=arm64-v8a \
+ -DANDROID_NDK="${ANDROID_NDK_PATH}"
make -j4 grpc_csharp_ext
+