简体   繁体   中英

Create Working Android Module in Appcelerator

I have been given the task of adding new features to a mobile app written in Appcelerator Studio. The owner of the app requested a feature that is not easily supported using Appcelerator's API, but it is readily supported with native code in Android and iOS. My task is to integrate native Android and iOS code into Appcelerator code.

I am struggling with integrating the Android code. I followed the instructions on this page: https://wiki.appcelerator.org/display/guides2/Android+Module+Quick+Start , but the application throws errors when I run it on an Android device through a USB cable. Here is the error that appears on the Android device:

Location:
[43/42] alloy/controllers/indes.js

Message:
Uncaught TypeError: Object#<View> has no method 'getExampleProp'

Source:
Ti.API.info("exampleProp: " + $.test.getExampleProp());

As mentioned in the aforementioned web page, Someone else asked about the same thing happening in January, but an answer has not been posted there as of yet.

What am I doing wrong?

Here is my code for the Hello app.

tiapp.xml:

<?xml version="1.0" encoding="UTF-8"?>
<ti:app xmlns:ti="http://ti.appcelerator.org">
    <id>com.example.hello</id>
    <name>hello</name>
    <version>1.0</version>
    <publisher>user</publisher>
    <url/>
    <description/>
    <copyright>2016 by user</copyright>
    <icon>appicon.png</icon>
    <fullscreen>false</fullscreen>
    <navbar-hidden>false</navbar-hidden>
    <analytics>true</analytics>
    <guid>877d5eaf-034e-4df6-9fff-a2de5a005994</guid>
    <property name="ti.ui.defaultunit" type="string">dp</property>
    <ios>
        <enable-launch-screen-storyboard>true</enable-launch-screen-storyboard>
        <plist>
            <dict>
                <key>UISupportedInterfaceOrientations~iphone</key>
                <array>
                    <string>UIInterfaceOrientationPortrait</string>
                </array>
                <key>UISupportedInterfaceOrientations~ipad</key>
                <array>
                    <string>UIInterfaceOrientationPortrait</string>
                    <string>UIInterfaceOrientationPortraitUpsideDown</string>
                    <string>UIInterfaceOrientationLandscapeLeft</string>
                    <string>UIInterfaceOrientationLandscapeRight</string>
                </array>
                <key>UIRequiresPersistentWiFi</key>
                <false/>
                <key>UIPrerenderedIcon</key>
                <false/>
                <key>UIStatusBarHidden</key>
                <false/>
                <key>UIStatusBarStyle</key>
                <string>UIStatusBarStyleDefault</string>
            </dict>
        </plist>
    </ios>
    <android xmlns:android="http://schemas.android.com/apk/res/android"/>
    <mobileweb>
        <precache/>
        <splash>
            <enabled>true</enabled>
            <inline-css-images>true</inline-css-images>
        </splash>
        <theme>default</theme>
    </mobileweb>
    <modules>
        <module platform="commonjs">ti.cloud</module>

        <!-- This is the relevant part. -->
        <module platform="android">com.example.test</module>
    </modules>
    <deployment-targets>
        <target device="android">true</target>
        <target device="ipad">true</target>
        <target device="iphone">true</target>
        <target device="mobileweb">true</target>
        <target device="windows">false</target>
    </deployment-targets>
    <sdk-version>5.3.0.GA</sdk-version>
    <plugins>
        <plugin version="1.0">ti.alloy</plugin>
    </plugins>
    <!-- Various properties associated with oauth. -->
</ti:app>

alloy.js:

var test = require('com.example.test');
Ti.API.info("module is => " + test);
Ti.API.info("module example() method returns => " + test.example());
Ti.API.info("module exampleProp is => " + test.exampleProp);
test.exampleProp = "This is a test value";

index.js:

$.index.open();
$.test.exampleProp = 'foobar';

// This breaks the application.
//Ti.API.info('exampleProp: ' + $.test.getExampleProp());

// This works.
Ti.API.info('exampleProp: ' + $.test.exampleProp);

// This breaks the application
//Ti.API.info('foo: ' + $.test.getFoo());

// This breaks the application.
//Test.createExample({message: "hello world"});

var view = test.createExample({
    color: 'blue',
    height: 50,
    width: 50
});

// This breaks the application.
//win.add(view);

// This has no effect.
$.index.add(view);

index.xml:

<Alloy>
    <Window class="container">
        <Module id="test" module="com.example.test" method="createView" height="50" width="50" color="red"/>
    </Window>
</Alloy>

Here is the code for the test module:

ExampleProxy.java:

/**
* This file was auto-generated by the Titanium Module SDK helper for Android
* Appcelerator Titanium Mobile
* Copyright (c) 2009-2010 by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the Apache Public License
* Please see the LICENSE included with this distribution for details.
*
*/
package com.example.test;

import org.appcelerator.kroll.KrollDict;
import org.appcelerator.kroll.KrollProxy;
import org.appcelerator.kroll.annotations.Kroll;
import org.appcelerator.titanium.TiC;
import org.appcelerator.titanium.util.Log;
import org.appcelerator.titanium.util.TiConfig;
import org.appcelerator.titanium.util.TiConvert;
import org.appcelerator.titanium.proxy.TiViewProxy;
import org.appcelerator.titanium.view.TiCompositeLayout;
import org.appcelerator.titanium.view.TiCompositeLayout.LayoutArrangement;
import org.appcelerator.titanium.view.TiUIView;

import android.app.Activity;


import org.appcelerator.kroll.KrollDict;
import org.appcelerator.kroll.annotations.Kroll;
import org.appcelerator.kroll.common.AsyncResult;
import org.appcelerator.kroll.common.TiMessenger;
import org.appcelerator.titanium.TiApplication;
import org.appcelerator.titanium.TiC;
import org.appcelerator.titanium.util.TiConvert;
import org.appcelerator.titanium.proxy.TiViewProxy;
import org.appcelerator.titanium.view.TiCompositeLayout;
import org.appcelerator.titanium.view.TiCompositeLayout.LayoutArrangement;
import org.appcelerator.titanium.view.TiUIView;
import android.app.Activity;
import android.os.Handler;
import android.os.Message;
import android.view.View;


// This proxy can be created by calling Test.createExample({message: "hello world"})
@Kroll.proxy(creatableInModule=TestModule.class)
public class ExampleProxy extends TiViewProxy
{    
    private static final int MSG_SET_COLOR = 70000;
    private static final String PROPERTY_COLOR = "color";

    private class ExampleView extends TiUIView
    {
        public ExampleView(TiViewProxy proxy) {
            super(proxy);
            LayoutArrangement arrangement = LayoutArrangement.DEFAULT;
            if (proxy.hasProperty(TiC.PROPERTY_LAYOUT)) {
                String layoutProperty = TiConvert.toString(proxy.getProperty(TiC.PROPERTY_LAYOUT));
                if (layoutProperty.equals(TiC.LAYOUT_HORIZONTAL)) {
                    arrangement = LayoutArrangement.HORIZONTAL;
                } else if (layoutProperty.equals(TiC.LAYOUT_VERTICAL)) {
                    arrangement = LayoutArrangement.VERTICAL;
                }
            }
            setNativeView(new TiCompositeLayout(proxy.getActivity(), arrangement));
        }
        @Override
        public void processProperties(KrollDict props) 
        {
            super.processProperties(props);

            // Check if the color is specified when the view was created
            if (props.containsKey(PROPERTY_COLOR)) {
                View square = (View)getNativeView();
                square.setBackgroundColor(TiConvert.toColor(props, PROPERTY_COLOR));            
                square.invalidate();
            }
        }        
        // Setter method called by the proxy when the 'color' property is set.
        public void setColor(String color) 
        {            
            // Use the TiConvert method to get the values from the arguments
            int newColor = TiConvert.toColor(color);
            View square = (View)getNativeView();
            square.setBackgroundColor(newColor);
        }        
    }

    @Override
    public TiUIView createView(Activity activity)
    {
        TiUIView view = new ExampleView(this);
        view.getLayoutParams().autoFillsHeight = true;
        view.getLayoutParams().autoFillsWidth = true;
        return view;
    }
    @Kroll.setProperty(retain=false)
    public void setColor(final String color) 
    {    
        // Get the view object from the proxy and set the color
        if (view != null) {
            if (!TiApplication.isUIThread()) {
                // If we are not on the UI thread, need to use a message to set the color
                TiMessenger.sendBlockingMainMessage(new Handler(TiMessenger.getMainMessenger().getLooper(), new Handler.Callback() {
                    public boolean handleMessage(Message msg) {
                        switch (msg.what) {
                            case MSG_SET_COLOR: {
                                AsyncResult result = (AsyncResult) msg.obj;
                                ExampleView fooView = (ExampleView)view;
                                fooView.setColor(color);
                                result.setResult(null);
                                return true;
                            }
                        }
                        return false;
                    }
                }).obtainMessage(MSG_SET_COLOR), color);
            } else {
                ExampleView fooView = (ExampleView)view;
                fooView.setColor(color);
            }
        }
        // Updates the property on the JavaScript proxy object
        setProperty("color", color, true);
    }
}

TestModule.java:

/**
* This file was auto-generated by the Titanium Module SDK helper for Android
* Appcelerator Titanium Mobile
* Copyright (c) 2009-2010 by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the Apache Public License
* Please see the LICENSE included with this distribution for details.
*
*/
package com.example.test;

import org.appcelerator.kroll.KrollModule;
import org.appcelerator.kroll.annotations.Kroll;

import org.appcelerator.titanium.TiApplication;
import org.appcelerator.kroll.common.Log;
import org.appcelerator.kroll.common.TiConfig;

@Kroll.module(name="Test", id="com.example.test", propertyAccessors = {"exampleProp"})
public class TestModule extends KrollModule
{

    // Standard Debugging variables
    private static final String LCAT = "TestModule";
    private static final boolean DBG = TiConfig.LOGD;
    private String foo;

    // You can define constants with @Kroll.constant, for example:
    // @Kroll.constant public static final String EXTERNAL_NAME = value;

    public TestModule()
    {
        super();
    }

    @Kroll.onAppCreate
    public static void onAppCreate(TiApplication app)
    {
        Log.d(LCAT, "inside onAppCreate");
        // put module init code that needs to run when the application is created
    }

    // Methods
    @Kroll.method
    public String example()
    {
        Log.d(LCAT, "example called");
        return "hello world";
    }

    // Properties
    @Kroll.getProperty
    public String getExampleProp()
    {
        Log.d(LCAT, "get example property");
        return foo;
    }


    @Kroll.setProperty
    public void setExampleProp(String value) {
        Log.d(LCAT, "In Module - the new value for exampleProp:" + foo);
        foo = value;
    }

    @Kroll.method
    public String getFoo() {
        return foo;
    }

}

This exampleProp is a property, you have to access a property in a different way than a function.

Just try following, change from

Ti.API.info("exampleProp: " + $.test.getExampleProp());

to:

Ti.API.info("exampleProp: " + $.test.exampleProp);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM