So for android devices there is a default share intent function that you call that will list all the apps that is downloaded on the device with that allows sharing of content. How would I do this using robovm, here is a Screen shot of what I am trying to achieve. Also on a side note, what I want to ultimately do is take a screenshot of their device and post it to whatever social media site the user chooses. Any help would be greatly appreciated :D
For iOS users:
RoboVM is deprecated in favor of RoboPods. So, RoboVM is no more, what now?
https://github.com/robovm/robovm-robopods/tree/master
For sharing text using roboVM, you can set the UIAvtivityViewController class
NSString textShare = new NSString("This is the text to share");
NSArray texttoshare = new NSArray(textShare);
UIActivityViewController share = new UIActivityViewController(texttoshare,null);
presentViewController(share, true, null);
For sharing text, image and app, you can do the following code,
NSURL imgUrl = new NSURL(EXTERNAL_IMG_URL);
NSData data = NSData.read(imgUrl);
UIImage image = new UIImage(data);
NSString appStoreUrl = new NSString(APP_STORE_URL);
NSString googleUrl = new NSString(GOOGLE_PLAY_URL);
NSString text = new NSString(TEXT_TO_SHARE);
NSArray<NSObject> texttoshare = new NSArray<NSObject>(text, image, appStoreUrl, googleUrl);
UIActivityViewController share = new UIActivityViewController(
texttoshare, null);
if (UIDevice.getCurrentDevice().getUserInterfaceIdiom() == UIUserInterfaceIdiom.Phone) {
//iPhone
iosApplication.getUIViewController().presentViewController(
share, true, null);
} else {
//iPad
UIPopoverController popover = new UIPopoverController(share);
UIView view = iosApplication.getUIViewController().getView();
CGRect rect = new CGRect(
view.getFrame().getWidth() / 2,
view.getFrame().getHeight() / 4,
0,
0);
popover.presentFromRectInView( rect, view, UIPopoverArrowDirection.Any, true);
}
The following code sends an animated .gif through Mail and Messenger, however, Twitter only shares a static image.
public void shareGif(String path)
{
NSURL url = new NSURL(new File(path));
NSArray<NSObject> imageArray = new NSArray<NSObject>(image);
UIActivityViewController share = new UIActivityViewController(imageArray,null);
((IOSApplication)Gdx.app).getUIViewController().presentViewController(share, true, null);
}
For generic share in iOS, with text, link and image the code is given below:
#Override
public void share() {
NSArray<NSObject> items = new NSArray<>(
new NSString("Hey! Check out this mad search engine I use"),
new NSURL("https://www.google.com"),
new UIImage(Gdx.files.external("image.png").file())
);
UIActivityViewController uiActivityViewController = new UIActivityViewController(items, null);
((IOSApplication) Gdx.app).getUIViewController().presentViewController(uiActivityViewController, true, null);
}
For Android users: Sharing Content with intents
It says RoboVM is for iOS only, So how would we use it for android using LibGDX?
roboVM with RoboPods is used for iOS while google play services is used for android. Different devices, different code. For android, after integrating the android sdk to your IDE, just link the google play services lib to the android project.
Related
This is the qr-code generator, I put on String qrCodeData to try access the storage of my phone and open up a file, but it doesnt work. Turns out the generated qr code only gives the link.
public class QRCode {
public static void main(String[] args) {
try {
String qrCodeData = "Device storage/Download/japanese/Mastering_Kanji_1500.pdf";
String filePath = "D:\\QR code project\\Generated QR codes\\qr.png";
String charset = "UTF-8"; // or "ISO-8859-1"
Map < EncodeHintType, ErrorCorrectionLevel > hintMap = new HashMap < EncodeHintType, ErrorCorrectionLevel > ();
hintMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
BitMatrix matrix = new MultiFormatWriter().encode(
new String(qrCodeData.getBytes(charset), charset),
BarcodeFormat.QR_CODE, 200, 200, hintMap);
MatrixToImageWriter.writeToFile(matrix, filePath.substring(filePath
.lastIndexOf('.') + 1), new File(filePath));
System.out.println("QR Code image created successfully! and stored at location"+filePath);
} catch (Exception e) {
System.err.println(e);
}
}
}
We are able to view and manipulate PDF files via the PDFBox library.
Android version.
We may also use MuPDF. It has an Android version.
Interpret the received link as a file or download it to storage, then proceed to interface with PDFBox library.
Note that file downloading and access on Android should now be done via Room interface or SQLite as recommended by Google.
Hope this helps.
I am working on a game and what I want to do is take a screenshot when the player dies and upload that image using the iOS sharesheet functionality to share to twitter, facebook etc... I have the image stored locally.
Here is my code for sharing an image link, but I want to upload a local image instead.
Any help would be much appreciated.
public void Share(int score)
{
UIViewController rootViewController = new UIViewController();
NSURL url = new NSURL("http://i.imgur.com/iWKad22.jpg");
NSData data = NSData.read(url);
UIImage image = new UIImage(data);
NSString textShare = new NSString("My Score: " + score + "! #Udderpanic");
NSArray<NSObject> textToShare = new NSArray<NSObject>(textShare, image);
UIActivityViewController share = new UIActivityViewController(textToShare,null);
((IOSApplication)Gdx.app).getUIViewController().addChildViewController(rootViewController);
if(UIDevice.getCurrentDevice().getModel().contentEquals("iPad"))
{
final UIPopoverController popoverController = new UIPopoverController(share);
popoverController.presentFromRectInView(new CGRect(0, 400, 0, 400), rootViewController.getView(), UIPopoverArrowDirection.Right, true);
}
else
{
rootViewController.presentViewController(share, true, null);
}
}
I am looking into the PDF renderer API native to Google Android development. I see the following code example in the documentation:
// create a new renderer
PdfRenderer renderer = new PdfRenderer(getSeekableFileDescriptor());
// let us just render all pages
final int pageCount = renderer.getPageCount();
for (int i = 0; i < pageCount; i++) {
Page page = renderer.openPage(i);
// say we render for showing on the screen
page.render(mBitmap, null, null, Page.RENDER_MODE_FOR_DISPLAY);
// do stuff with the bitmap
// close the page
page.close();
}
// close the renderer
renderer.close();
I think this example uses from File Object. How I can get this API to work with a URL from a webserver, such as a document from a website? How can I load a PDF natively in an Android app that does not require a download of the file onto the local storage? Something like how you can run the Google docs viewer to open the PDF in webview - but I cannot take that approach because the Google docs viewer is blocked in the environment I am in.
You cannot use Pdf Renderer to load URL. But your can make use of Google Docs in your webview to load URL without downloading the file...
webView.loadUrl("https://docs.google.com/gview?embedded=true&url=" + YOUR_URL);
how I can get this API to work with URL from a webserver?
Download the PDF from the server to a local file. Then, use the local file.
The purpose of what I am trying to learn is how to load pdf natively in android app that does not require a download of the file onto the local storage
AFAIK, you cannot use PdfRenderer that way. It needs a seekable FileDescriptor, and the only way that I know of to create one of those involves a local file.
I would first download the pdf and then show it in a pdfView
private fun downloadPdf(): File? {
val client = OkHttpClient()
val request = Request.Builder().url(urlString)
.addHeader("Content-Type", "application/json")
.build()
val response = client.newCall(request).execute()
val inputStream: InputStream? = response.body?.byteStream()
val pdfFile = File.createTempFile("myFile", ".pdf", cacheDir)
inputStream?.readBytes()?.let { pdfFile.writeBytes(it) }
return pdfFile
}
and then do something like this:
CoroutineScope(IO).launch {
val pdfDownloaded = downloadPdf()
if (pdfDownloaded != null) {
pdfView.fromFile(pdfDownloaded)
}
withContext(Main) {
pdfView.visibility = View.VISIBLE
hideProgress()
pdfView.show()
}
}
here
I can't find how to get ListArray variables from an AndroidJavaObject in C#.
I'm trying to make a for function using a Count for the number of items in the ListArray that is stored as an AndroidJavaObject. But I need to know how to get the Count from the AndroidJavaObject and how to use it properly.
This is what I'm using to get the variables, also notice that "packages" is not an AndroidJavaObject[].
AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject currentActivity = jc.GetStatic<AndroidJavaObject>("currentActivity");
int flag = new AndroidJavaClass("android.content.pm.PackageManager").GetStatic<int>("GET_META_DATA");
AndroidJavaObject pm = currentActivity.Call<AndroidJavaObject>("getPackageManager");
AndroidJavaObject packages = pm.Call<AndroidJavaObject>("getInstalledApplications", flag);
it's very rudimentary at this point, but it works thanks to some help from this How to get installed apps list with Unity3D?
The progress thus far stalls at getting the icon, everything else works perfect, I need a way to get either a string that links to the icon somehow, or the Texture2D of the icon. Another alternative would be a to use a AndroidJavaObject that contains a drawable as if it's a Texture2D. I have no idea how to accomplish any of this though.Another Idea I had was to convert it to another variable, like byte[] that can be transferred and converted back, but I have yet to find a method of that which works under the circumstance.
int count = packages.Call<int>("size");
AndroidJavaObject[] links = new AndroidJavaObject[count];
string[] names = new string[count];
Texture2D[] icons = new Texture2D[count];
int ii =0;
for(int i=0; ii<count;){
//get the object
AndroidJavaObject currentObject = packages.Call<AndroidJavaObject>("get", ii );
try{
//try to add the variables to the next entry
links[i] = pm.Call<AndroidJavaObject>("getLaunchIntentForPackage", currentObject.Get<AndroidJavaObject>("processName"));
names[i] = pm.Call<string>("getApplicationLabel", currentObject);
icons[i] = pm.Call<Texture2D>("getApplicationIcon", currentObject);
Debug.Log ("(" + ii + ") " + i +" "+ names[i]);
//go to the next app and entry
i++;
ii++;
}
catch
{
//if it fails, just go to the next app and try to add to that same entry.
Debug.Log("skipped "+ ii);
ii++;
}
}
I really hate to ask two questions in a row here, and I apologize for having to do so, but this is a difficult and seemingly awkward circumstance, that has little to no documentation (that I can find).
First of all the docs on the interop between Unity3D and Android are scarce at best.
The most important thing is that the only interface Unity exposes to work with java object is AndroidJavaObject and that interface has only a couple of methods defined. You can only use those ones and only those.
This means that you don't get a Count object when working with an java array and you'll still be working with AndroidJavaObject.
int count = packages.Call<int>("size"); //getting the size of the array
for( int i = 0; i < count; i++ )
{
//getting the object at location i
AndroidJavaObject currentObject = packages.Call("get", i );
//use currentObject using the same methods as before: Call, CallStatic, Get, GetStatic
}
I know this is verbose, and writing code like this is hard to test, you need to make and apk and deploy it to a device to check that it runs.
Probably a faster way of doing this is to make your own java class that does all this on the java side and expose one method that gets called from the Unity side. This way at least you get the benefit of static typing when making a jar that you'll add in the Plugins/Android folder.
I'm trying to do the same thing here, but my launcher must only show the CardBoard apps. What i've decided is to make a library in java and import it to Unity as a plugin:
This is my Java class:
public class Launcher extends UnityPlayerActivity {
private List<ApplicationInfo> cbApps;
#Override
protected void onStart() {
super.onStart();
PackageManager pm= getPackageManager();
List<ApplicationInfo> lista = pm.getInstalledApplications(PackageManager.GET_META_DATA);
cbApps= new LinkedList<ApplicationInfo>();
for(ApplicationInfo ai : lista){
Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
intentToResolve.addCategory("com.google.intent.category.CARDBOARD");
intentToResolve.setPackage(ai.packageName);
if(pm.resolveActivity(intentToResolve, 0)!=null) {
cbApps.add(ai);
}
}
}
public int getListSize(){
return cbApps.size();
}
And here my C# method:
void Start () {
AndroidJavaClass unity = new AndroidJavaClass ("com.unity3d.player.UnityPlayer");
AndroidJavaObject currentActivity = unity.GetStatic<AndroidJavaObject> ("currentActivity");
texto.text=""+currentActivity.Call<int> ("getListSize");
}
This way I can create in Java every method that I need to acces the list. The problem I'm still having is trying to get the Texture2D of the icons. I've tried returning the Drawable from Java and accesing with a Call just as you did, but it doesn't work at all. I've been 2 days working with that, I'll let you know if I find a solution.
EDIT:
Finally I could get the images:
First in Java I created this method:
public byte[] getIcon(int i) {
BitmapDrawable icon= (BitmapDrawable)context.getPackageManager().getApplicationIcon(cbApps.get(i));
Bitmap bmp = icon.getBitmap();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
return byteArray;
}
That way I can access the Byte array representing the Drawable from Unity and show it as the main texture of a Plane:
void Start () {
using (AndroidJavaClass unity = new AndroidJavaClass ("com.unity3d.player.UnityPlayer")) {
context = unity.GetStatic<AndroidJavaObject> ("currentActivity");
}
using (AndroidJavaClass pluginClass=new AndroidJavaClass("com.droiders.launcher.Launcher")) {
launcher= pluginClass.CallStatic<AndroidJavaObject>("getInstance", context);
byte[] bytes= launcher.Call<byte[]>("getIcon",0);
Texture2D tex= new Texture2D(2,2);
tex.LoadImage(bytes);
plane.GetComponent<Renderer>().material.mainTexture=tex;
}
}
Hope it helps you. It's been hard but this beast has been tamed :P
Also thanks you all for your ideas.
I am having trouble with this code,
#Path("/play")
public class Player {
#GET
#Produces("audio/mpeg")
public Response get(#DefaultValue("C:\\Users\\Ben\\Music\\sample.mp3") #QueryParam("file") String file) {
File song = new File(file);
return Response.ok().entity(song).build();
}
}
Chrome is able to play the content returned from this, but Safari mobile can't.
When I move the sample.mp3 into static web folder it is able to play in Safari mobile browser.
How can I get mobile Safari to play audio returned using JAX-RS?
I used the AudioAttributes and EncodingAttributes classes to convert the file to the right codec. It's pretty slow and wastes a lot of storage because a new file has to be create each time a song is played. I'll probably change this code later so that the files are cached after converted. Then before I convert I check if I already converted. Also it would be nice to test if the raw file is compatible with the device before converting it. Here's current the code.
#GET
#Path("/audio")
#Produces("audio/mpeg")
public Response getAudio(
#DefaultValue("C:\\Users\\Ben\\Music\\sample.mp3") #QueryParam("file") String file,
#DefaultValue("medium") #QueryParam("quality") String quality) throws EncoderException, IOException {
File song = new File(file);
File rootMusicDir = new File(AUDIO_PATH);
File rootVideoDir = new File(VIDEO_PATH);
if (!directoryService.isSubDirectory(rootMusicDir, song) && !directoryService.isSubDirectory(rootVideoDir, song)) {
return Response.status(500).build();
}
AudioAttributes audio = new AudioAttributes();
audio.setCodec("libmp3lame");
if (quality.equalsIgnoreCase("high")) {
audio.setBitRate(new Integer(256000));
audio.setChannels(new Integer(2));
audio.setSamplingRate(new Integer(44100));
} else if (quality.equalsIgnoreCase("medium")) {
audio.setBitRate(new Integer(128000));
audio.setChannels(new Integer(2));
audio.setSamplingRate(new Integer(44100));
} else {
audio.setBitRate(new Integer(64000));
audio.setChannels(new Integer(1));
audio.setSamplingRate(new Integer(22050));
}
EncodingAttributes attrs = new EncodingAttributes();
attrs.setFormat("mp3");
attrs.setAudioAttributes(audio);
Encoder encoder = new Encoder();
String random = new BigInteger(130, new SecureRandom()).toString(32);
File songMP4 = new File(TEMP_PATH + file.replaceAll("[^\\dA-Za-z ]", "").replaceAll("\\s+", "+") + random);
encoder.encode(song, songMP4, attrs);
return Response.ok().entity(songMP4).build();
}
Could you clarify what the root cause of your problem was? I don't quite follow why re-encoding the file should solve the problem? From what I understood, you have an .mp3 which works fine in Safari mobile when served statically, but not when served as per your code above. I presume, therefore, that your original .mp3 is encoded in a fashion that iOS can cope with (or else the statically served file would not play correctly).
Could there be an issue with the headers that you are sending along with the served .mp3? The reason I ask is that I have a similar problem serving an mp3 to mobile Safari which is served by a Perl script. Works fine when files statically served. When the same file is served using Perl it gives 404 in Safari mobile (Safari on OSX works fine).