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 +