As from the program .NET MAUI pass AssetManager to the C++ library - c#

The AssetManager received in C# (MAUI for Android) is accepted by the library, but does not work when trying to use it. How to pass the AssetManager correctly or how to get value of AAssetManager *pAssetManager?
C# code:
#if ANDROID
[DllImport("library.so", EntryPoint = "SetAsset")]
public static extern void SetAsset(IntPtr env, Android.Runtime.IJavaObject assetManager);
#endif
void Proc()
{
var env = Environment.EnvironmentPointer; // JNIEnv *env
AssetManager assets = Android.App.Application.Context.Assets; // jobject
SetAsset(env, assets);
}
library.so code:
void SetAsset(JNIEnv *env, jobject assetManager)
{
AAssetManager *pAssetManager = AAssetManager_fromJava(env, assetManager); // ERROR in this point
...
}

Related

Xamarin Forms: Platform specific code does not show xaml file

I have a native sdk in my Xamarin Forms which does nothing. I have a xaml file behind the platform specific .cs file but the contents are not displayed.
Main file
private async void Video()
{
DependencyService.Get<InterfaceFile>().GetNativeMethod();
}
Interface file
public interface InterfaceFile
{
void GetNativeMethod();
}
Native file:
[assembly: Xamarin.Forms.Dependency(typeof(Demo))]
namespace Demo.Droid
{
public partial class Demo : InterfaceFile
{
public string GetNativeMthod()
{
/// code
}
}
}
The above platform specific code has video implementation using third party native sdks. I have xaml code behind this file.
I want to start this video call in this xaml file, which is not happening. How to bind the xaml file to .cs file?
Edit
I have tried removing the xaml code, and added only .cs file with following code(using Vidyo native sdk):
public void GetNativeMethod()
{
_vidyoConnector = new Connector(viewHandle,Connector.ConnectorViewStyle.ConnectorviewstyleDefault, 16, "warning all#VidyoConnector info#VidyoClient", "", 0);
_vidyoConnector.ShowViewAt(viewHandle, 0, 0, viewWidth, viewHeight);
_vidyoConnector.Connect(host, token, displayName, resourceId, this);
}
With above code, app crashes because frame is not defined here.
Native sdk code for Connector method:
public Connector(IntPtr viewId, ConnectorViewStyle viewStyle, uint remoteParticipants, String logFileFilter, String logFileName, ulong userData){
IntPtr nLogFileFilter = MarshalPtrToUtf8.GetInstance().MarshalManagedToNative(logFileFilter ?? string.Empty);
IntPtr nLogFileName = MarshalPtrToUtf8.GetInstance().MarshalManagedToNative(logFileName ?? string.Empty);
objPtr = VidyoConnectorConstructNative(ref viewId, viewStyle, remoteParticipants, nLogFileFilter, nLogFileName, userData);
Marshal.FreeHGlobal(nLogFileName);
Marshal.FreeHGlobal(nLogFileFilter);
VidyoConnectorSetUserDataNative(objPtr, GCHandle.ToIntPtr(GCHandle.Alloc(this, GCHandleType.Weak)));
}
Documentation reference for vidyo: https://developer.vidyo.io/#/documentation

How to use the gRPC tools to generate code

I've read the tutorial and I'm able to generate the .cs file but it doesn't include any of my service or rpc definitions.
I've added protoc to my PATH and from inside the project directory.
protoc project1.proto --csharp_out="C:\output" --plugin=protoc-gen-grpc="c:\Users\me\.nuget\packages\grpc.tools\1.8.0\tools\windows_x64\grpc_csharp_plugin.exe"
No errors output in console
You need to add the --grpc_out command line option, e.g. add
--grpc_out="C:\output\"
Note that it won't write any files if you don't have any services.
Here's a complete example. From a root directory, create:
An empty output directory
A tools directory with protoc.exe and grpc_csharp_plugin.exe
A protos directory with test.proto as shown below:
test.proto:
syntax = "proto3";
service StackOverflowService {
rpc GetAnswer(Question) returns (Answer);
}
message Question {
string text = 1;
string user = 2;
repeated string tags = 3;
}
message Answer {
string text = 1;
string user = 2;
}
Then run (all on one line; I've broken it just for readability here):
tools\protoc.exe -I protos protos\test.proto --csharp_out=output
--grpc_out=output --plugin=protoc-gen-grpc=tools\grpc_csharp_plugin.exe
In the output directory, you'll find Test.cs and TestGrpc.cs
Just an idle comment here for other that find this, the documentation about this is terribly out of date and just flat out wrong.
Installing Grpc.Tools does not install anything in a packages folder; that is legacy behaviour which is no longer true even on windows.
When you install Grpc.Tools it will be hidden away in your local package cache, which you can see by calling:
$ dotnet nuget locals all --list
info : http-cache: /Users/doug/.local/share/NuGet/v3-cache
info : global-packages: /Users/doug/.nuget/packages/
info : temp: /var/folders/xx/s2hnzbrj3yn4hp1bg8q9gb_m0000gn/T/NuGetScratch
The binaries you want will be in one of these folders.
The easiest way to do this is to download the Grpc.Tools package directly from nuget, and install it locally.
I've hacked up this little helper script to do that, which works on windows/mac/linux, which may ease the difficulty of getting starting with this for others:
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Mono.Unix;
namespace BuildProtocol
{
public class Program
{
private const string ToolsUrl = "https://www.nuget.org/api/v2/package/Grpc.Tools/";
private const string Service = "Greeter";
private static string ProtocolPath = Path.Combine("..", "protos");
private static string Protocol = Path.Combine(ProtocolPath, "helloworld.proto");
private static string Output = Path.Combine("..", "Greeter");
public static void Main(string[] args)
{
RequireTools().Wait();
var protoc = ProtocPath();
var plugin = ProtocPluginPath();
Console.WriteLine($"Using: {protoc}");
Console.WriteLine($"Using: {plugin}");
var command = new string[]
{
$"-I{ProtocolPath}",
$"--csharp_out={Output}",
$"--grpc_out={Output}",
$"--plugin=protoc-gen-grpc=\"{plugin}\"",
Protocol,
};
Console.WriteLine($"Exec: {protoc} {string.Join(' ', command)}");
var process = new Process
{
StartInfo = new ProcessStartInfo
{
UseShellExecute = false,
FileName = protoc,
Arguments = string.Join(' ', command)
}
};
process.Start();
process.WaitForExit();
Console.WriteLine($"Completed status: {process.ExitCode}");
}
public static async Task RequireTools()
{
if (!Directory.Exists("Tools"))
{
Console.WriteLine("No local tools found, downloading binaries from nuget...");
Directory.CreateDirectory("Tools");
await DownloadTools();
ExtractTools();
}
}
private static void ExtractTools()
{
ZipFile.ExtractToDirectory(Path.Combine("Tools", "tools.zip"), Path.Combine("Tools", "bin"));
}
private static async Task DownloadTools()
{
using (var client = new HttpClient())
{
Console.WriteLine($"Fetching: {ToolsUrl}");
using (var result = await client.GetAsync(ToolsUrl))
{
if (!result.IsSuccessStatusCode) throw new Exception($"Unable to download tools ({result.StatusCode}), check URL");
var localArchive = Path.Combine("Tools", "tools.zip");
Console.WriteLine($"Saving to: {localArchive}");
File.WriteAllBytes(localArchive, await result.Content.ReadAsByteArrayAsync());
}
}
}
private static string ProtocPath()
{
var path = Path.Combine("Tools", "bin", "tools", DetermineArch(), "protoc");
RequireExecutablePermission(path);
return WithExeExtensionIfRequired(path);
}
private static string ProtocPluginPath()
{
var path = Path.Combine("Tools", "bin", "tools", DetermineArch(), "grpc_csharp_plugin");
RequireExecutablePermission(path);
return WithExeExtensionIfRequired(path);
}
private static void RequireExecutablePermission(string path)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return;
Console.WriteLine($"Ensuring +x on {path}");
var unixFileInfo = new UnixFileInfo(path);
unixFileInfo.FileAccessPermissions = FileAccessPermissions.UserRead | FileAccessPermissions.UserWrite | FileAccessPermissions.UserExecute;
}
private static string WithExeExtensionIfRequired(string path)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
path += ".exe";
}
return path;
}
private static string DetermineArch()
{
var arch = RuntimeInformation.OSArchitecture;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return WithArch("windows_", arch);
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
return WithArch("macosx_", arch);
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
return WithArch("linux_", arch);
}
throw new Exception("Unable to determine runtime");
}
private static string WithArch(string platform, Architecture arch)
{
switch (arch)
{
case Architecture.X64:
return $"{platform}x86";
case Architecture.X86:
return $"{platform}x64";
default:
throw new ArgumentOutOfRangeException(nameof(arch), arch, null);
}
}
}
}
the following approach helped me :
Create a gRPC client and server in ASP.NET Core
in project, where .proto file located, edit the .csproj file
<ItemGroup>
....
<Protobuf Include="Shipping.proto" GrpcServices="Server" />
</ItemGroup>
rebuild the project, the all necessary .cs files will be added automaticaly
\obj\Debug\[TARGET_FRAMEWORK]\Shipping.cs
\obj\Debug\[TARGET_FRAMEWORK]\ShippingGrpc.cs

Xbim Geometry error

I am using the following C# code to access geometry data from an ifc4 file. The file contains only a wall created using Revit 2016. I am using Xbim library. This is my code:
class Program
{
private static readonly ILog logger =
LogManager.GetLogger(typeof(Program));
static string _ifcFile = #"C:\Examples\OneWall.ifc";
static void Main(string[] args)
{
BasicConfigurator.Configure();
IfcStore model = IfcStore.Open(_ifcFile);
Xbim3DModelContext context = new Xbim3DModelContext(model);
context.CreateContext();
XbimMeshGeometry3D mesh = mesh = (XbimMeshGeometry3D)context.ShapeGeometryMeshOf(context.ShapeInstances().FirstOrDefault());
//The rest of my code
}
}
I get the following error. I am using visual studio 2015.
1226 [1] DEBUG Xbim.Geometry.Engine.Interop.XbimCustomAssemblyResolver (null) - Loading assembly from: C:\Examples\ifcWall\ifcWall\bin\Debug\x86\Xbim.Geometry.Engine32.dll
1404 [1] DEBUG Xbim.Geometry.Engine.Interop.XbimCustomAssemblyResolver (null) - Loading assembly from: C:\Examples\ifcWall\ifcWall\bin\Debug\x86\Xbim.Geometry.Engine32.dll
Unhandled Exception: System.Exception: Invalid Geometry Command
at Xbim.ModelGeometry.Scene.XbimMeshGeometry3D.Read(String data, Nullable1 trans) in c:\BuildAgent\work\860c3b913b6c647f\Xbim.ModelGeometry.Scene\XbimMeshGeometry3D.cs:line 219
at Xbim.ModelGeometry.Scene.XbimMeshGeometry3D.Add(String mesh, Int16 productTypeId, Int32 productLabel, Int32 geometryLabel, Nullable1 transform, Int16 modelId) in c:\BuildAgent\work\860c3b913b6c647f\Xbim.ModelGeometry.Scene\XbimMeshGeometry3D.cs:line 669
at Xbim.ModelGeometry.Scene.Xbim3DModelContext.ShapeGeometryMeshOf(XbimShapeInstance shapeInstance) in c:\BuildAgent\work\860c3b913b6c647f\Xbim.ModelGeometry.Scene\Xbim3DModelContext.cs:line 1525
at ifcWall.Program.Main(String[] args) in C:\Users\karshenas\Documents\Courses\CEEN6840\VS_Projects\ifcWall\ifcWall\Program.cs:line 26
Any help to fix the error is appreciated.
You run into an area where API has changed and this particular functions expects data in a different format. If what you need is a triangulation of the shape this code should work for you:
using System.IO;
using Xbim.Common.Geometry;
using Xbim.Ifc;
using Xbim.ModelGeometry.Scene;
using Xbim.Common.XbimExtensions;
namespace CreateWexBIM
{
class Program
{
static void Main(string[] args)
{
const string file = #"4walls1floorSite.ifc";
var model = IfcStore.Open(file);
var context = new Xbim3DModelContext(model);
context.CreateContext();
var instances = context.ShapeInstances();
foreach (var instance in instances)
{
var geometry = context.ShapeGeometry(instance);
var data = ((IXbimShapeGeometryData)geometry).ShapeData;
using (var stream = new MemoryStream(data))
{
using (var reader = new BinaryReader(stream))
{
var mesh = reader.ReadShapeTriangulation();
}
}
}
}
}
}
The best is to ask in xBIM GitHub Issues and to share the file. IFC geometry can get very complex so it is not possible to really answer your question just based on the exception.

Take Photo in Xamarin Android with MvvmCross

I'm working on Xamarin Android project and I want to implement taking photo with MvvmCross.
Here's my code:
public class PhotoService:IPhotoService
{
private const int MaxPixelDimension = 1280;
private const int DefaultJpegQuality = 90;
private Stream imageStream;
public Stream ImageStream
{
get { return imageStream; }
set { imageStream = value; }
}
public void GetPhoto()
{
var task = Mvx.Resolve<IMvxPictureChooserTask>();
task.TakePicture(
MaxPixelDimension,
DefaultJpegQuality,
SavePicture, null);
}
private void SavePicture(Stream stream)
{
ImageStream = stream;
}
}
but in:
task.TakePicture(
MaxPixelDimension,
DefaultJpegQuality,
SavePicture,
null);
I have error:
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
UPDATE
in call stack I have:
0x0 in Android.Content.Intent..ctor at /Users/builder/data/lanes/3511/501e63ce/source/monodroid/src/Mono.Android/platforms/android-24/src/generated/Android.Content.Intent.cs:1275,6 C#
0x12 in MvvmCross.Plugins.PictureChooser.Droid.MvxPictureChooserTask.TakePicture C#
0x3A in App.Services.PhotoService.PhotoService.GetPhoto at C:\app\App.Services\PhotoService\PhotoService.cs:38,4 C#
0x7 in App.ViewModels.ViewModels.MainViewModel.TakePhoto at C:\app\App.ViewModels\ViewModels\MainViewModel.cs:49,4 C#
Alternative solution you can use Media Plugin that available in nuget
https://www.nuget.org/packages/Xam.Plugin.Media/
You can use dependency service to call the takePictureAsync method from android project. With this library you can specify file name and folder path to store your image. This library can also take video using takeVideoAsync method.
I believe you need to add the MVVMCross.Pugin.PictureChooser package to your Core and platform specific projects.

Load file downloaded iOS app created in Unity

I'm trying to load a json file downloaded and saved in the persistentDataPath of an iOS device. The download and save works great. However I think I have big issues to load the file. In fact when I try to compile the project in Xcode I have some errors messages.
First here is my C# code :
using UnityEngine;
using System.Collections;
using System.IO;
using System.Net;
using UnityEngine.UI;
public class ReadJson : MonoBehaviour
{
public Text City;
public Text Temperature;
public Image Weather;
public Text WeatherUrl;
[System.Serializable]
public class CityInfo
{
public string name;
}
[System.Serializable]
public class CurrentCondition
{
public string date;
public string hour;
public int tmp;
public int wnd_spd;
public int wnd_gust;
public string wnd_dir;
public double pressure;
public int humidity;
public string condition;
public string icon;
public string icon_big;
}
[System.Serializable]
public class RootObject
{
public CityInfo city_info;
public CurrentCondition current_condition;
}
void Start () {
WebClient client = new WebClient();
File.Delete(Path.Combine (Application.persistentDataPath, "myjson.json"));
client.DownloadFile ("http://www.myjsonurl", Path.Combine (Application.persistentDataPath, "myjson.json"));
TextAsset asset = Resources.Load (Path.Combine (Application.dataPath + "/Documents", "myjson")) as TextAsset;
RootObject m = JsonUtility.FromJson<RootObject> (asset.text);
City.text = m.city_info.name;
Temperature.text = (m.current_condition.tmp).ToString();
}
}
And now the xcode console :
2016-10-21 17:01:20.766001 json[1404:516674] [DYMTLInitPlatform] platform initialization successful
2016-10-21 17:01:20.929950 json[1404:516508] -> registered mono modules 0xb95f70
2016-10-21 17:01:21.356590 json[1404:516508] You've implemented -[<UIApplicationDelegate> application:didReceiveRemoteNotification:fetchCompletionHandler:], but you still need to add "remote-notification" to the list of your supported UIBackgroundModes in your Info.plist.
-> applicationDidFinishLaunching()
2016-10-21 17:01:21.452967 json[1404:516508] Metal GPU Frame Capture Enabled
2016-10-21 17:01:21.453369 json[1404:516508] Metal API Validation Enabled
-> applicationDidBecomeActive()
Init: screen size 750x1334
Initializing Metal device caps
Initialize engine version: 5.3.4f1 (fdbb5133b820)
UnloadTime: 1.705875 ms
Salut/var/mobile/Containers/Data/Application/51A2490E-94EB-4904-9F2E-112AD5632A98/Documents
(Filename: /Users/builduser/buildslave/unity/build/artifacts/generated/common/runtime/UnityEngineDebugBindings.gen.cpp Line: 37)
NullReferenceException: A null value was found where an object instance was required.
(Filename: currently not available on il2cpp Line: -1)
Setting up 1 worker threads for Enlighten.
Thread -> id: 19f17000 -> priority: 1
If someone has an idea. Thanks a lot in advance.
The problem with your code is on this line:
TextAsset asset = Resources.Load(Path.Combine(Application.dataPath + "/Documents", "myjson")) as TextAsset;
I don't think you understand how and when to use Resources.Load. If you want to use the Resources.Load function, you must create a special folder from the Editor. This folder should be at <ProjectDirectory>/Assets/Resources. You can only put/write stuff into this folder from the Editor. You can't do it after build on iOS. It becomes read only after you build it. This special folder can then be read with the Resources.Load function.
Replacing:
TextAsset asset = Resources.Load(Path.Combine(Application.dataPath + "/Documents", "myjson")) as TextAsset;
with
string text = File.ReadAllText(Path.Combine(Application.persistentDataPath, "myjson.json"));
RootObject m = JsonUtility.FromJson<RootObject>(text);
City.text = m.city_info.name;
Temperature.text = (m.current_condition.tmp).ToString();
Should solve your problem.
Another API that should not be using is WebClient. Unless you have a good reason to use that, you shouldn't. You should either use the WWW or UnityWebRequest(newer and recommended) API.
This is what your code should look like without WebClient:
void Start()
{
StartCoroutine(DownloadAndloadJson());
}
IEnumerator DownloadAndloadJson()
{
string url = "http://www.myjsonurl";
UnityWebRequest www = UnityWebRequest.Get(url);
yield return www.Send();
if (www.isError)
{
Debug.Log(www.error);
}
else
{
//Sucessfully downloaded the Json File
Debug.Log("Json: " + www.downloadHandler.text);
string jsonFile = www.downloadHandler.text;
//Delete old json file. Don't know why but this was in your original code
File.Delete(Path.Combine(Application.persistentDataPath, "myjson.json"));
//Save the downloaded data as File
File.WriteAllText(Path.Combine(Application.persistentDataPath, "myjson.json"), jsonFile);
//Load the downloaded data
string text = File.ReadAllText(Path.Combine(Application.persistentDataPath, "myjson.json"));
Debug.Log(text);
RootObject m = JsonUtility.FromJson<RootObject>(text);
City.text = m.city_info.name;
Temperature.text = (m.current_condition.tmp).ToString();
}
}
If you have problems please update to Unity 5.4. The UnityWebRequest API should be used for this and it was introduced in 5.3 but bugs were fixed in 5.4. You need using UnityEngine.Networking; to use UnityWebRequest.

Categories

Resources