Search code examples
javaandroidinterpreterbeanshell

Is it possible to create (NOT import) a new class in java using BeanShell?


I use BeanShell to dynamically manage interface and content in my android application. Today I faced the following problem: I need to process a class with an unknown structure for the application, that is, the server sends the code and the application processes it.

Below is one of my code handlers. The error is reported to the "public class LastNews{":

    import android.widget.LinearLayout;
    import android.widget.ScrollView;
    import android.widget.TextView;
    import android.graphics.Color;
    import android.view.ViewGroup;
    import android.util.TypedValue;
    import android.graphics.Typeface;
    import java.util.Random;
    import android.view.View;
    import android.widget.Toast;
    import apppackege.ViewCreator;
    import apppackege.Calculate;
    import android.widget.GridView;
    import android.widget.BaseAdapter;
    import apppackege.AdapterCreator;
    import apppackege.IconName;
    import com.google.gson.Gson;
    import com.google.gson.reflect.TypeToken;
    import apppackege.WrappingGridView;
    import java.util.ArrayList;
    import apppackege.Decoder;
    import apppackege.LoadImage;
    import android.widget.ImageView;

    LinearLayout topPanel = ViewCreator.linearLayout(context, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
            Calculate.dpToPixel(context, 40)), LinearLayout.HORIZONTAL);
    topPanel.setBackgroundColor(Color.parseColor("#1E88E5"));

    LinearLayout bottomPanel = ViewCreator.linearLayout(context, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
            Calculate.dpToPixel(context, 40)), LinearLayout.HORIZONTAL);
    bottomPanel.setBackgroundColor(Color.parseColor("#EFEFEF"));

    ScrollView scrollView = ViewCreator.scrollView(context, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
            ViewGroup.LayoutParams.MATCH_PARENT, 1.0f));
    scrollView.setBackgroundColor(Color.WHITE);

    parent.addView(topPanel);
    parent.addView(scrollView);
    parent.addView(bottomPanel);

    LinearLayout scrollLayout = ViewCreator.linearLayout(context,
            new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
            ViewGroup.LayoutParams.WRAP_CONTENT), -1);
    scrollView.addView(scrollLayout);

    ImageView topImage = ViewCreator.imageView(context, null, null);
    new LoadImage(topImage, "https://url.com/9tVFtRoOCIQ.jpg");
    scrollLayout.addView(topImage);

    WrappingGridView wrappingGridView = ViewCreator.wrappingGridView(context, null, 3);
    scrollLayout.addView(wrappingGridView);
    String jsonIconName = "[{\"icon\":\"https://url.com/thumb-up.png\",\"name\":\"ГОЛОС\",\"iconColor\":\"#1E88E5\"},{\"icon\":\"https://url.com/news.png\",\"name\":\"НОВОСТИ\",\"iconColor\":\"#1E88E5\"},{\"icon\":\"https://url.com/camping-tent.png\", \"name\": \"ТУРИЗМ\",\"iconColor\":\"#1E88E5\"},{\"icon\":\"https://url.com/image.png\",\"name\":\"ФОТО\",\"iconColor\":\"#1E88E5\"},{\"icon\":\"https://url.com/cafe.png\",\"name\":\"МЕСТА\",\"iconColor\":\"#1E88E5\"},{\"icon\":\"https://url.com/user.png\",\"name\":\"АККАУНТ\",\"iconColor\":\"#1E88E5\"},{\"icon\":\"https://url.com/cinema-.png\",\"name\":\"АФИША\",\"iconColor\":\"#1E88E5\"},{\"icon\":\"https://url.com/focal-length.png\",\"name\":\"КОНТРОЛЬ\",\"iconColor\":\"#1E88E5\"},{\"icon\":\"https://url.com/chase.png\",\"name\":\"ОХОТА\",\"iconColor\":\"#1E88E5\"}]";
    BaseAdapter baseAdapter = AdapterCreator.baseAdapterIconName(context, Decoder.fromJsonArray(jsonIconName, IconName.class));
    wrappingGridView.setAdapter(baseAdapter);
    ((BaseAdapter)wrappingGridView.getAdapter()).notifyDataSetInvalidated();

    TextView lineActual = ViewCreator.textView(context, "АКТУАЛЬНО",
            null, 10, 14, "#1E88E5", new View.OnClickListener() {
        public void onClick(View v) {
            Toast.makeText(context, "АКТУАЛЬНО", Toast.LENGTH_SHORT).show();
        }
    });
    scrollLayout.addView(lineActual);

    TextView lineNews = ViewCreator.textView(context, "СВЕЖИЕ НОВОСТИ",
            null, 10, 14, "#1E88E5", new View.OnClickListener() {
        public void onClick(View v) {
            Toast.makeText(context, "СВЕЖИЕ НОВОСТИ", Toast.LENGTH_SHORT).show();
        }
    });
    scrollLayout.addView(lineNews);
    String jsonNews = " [ { \"id\": \"89e94f07-2939-11ec-a3ee-e145f6ad5670\", \"head\": \"Белорус сделал предложение Бузовой в прямом эфире X Factor\", \"icon\": \"http://url.com/73fde9f1-a72f-43c0-a6e7-10957e216a9b.jpg\", \"type\": \"http://url.com/info.png\", \"location\": \"Беларусь\" }, { \"id\": \"c2833cf1-2928-11ec-a3ee-e145f6ad5670\", \"head\": \"Жители Приморья стоят в очередях за белорусскими продуктами - Богданов\", \"icon\": \"http://url.com/77e75355-4255-4cae-9962-fdb7394986c5.jpg\", \"type\": \"http://url.com/info.png\", \"location\": \"Беларусь\" }, { \"id\": \"c2833cf0-2928-11ec-a3ee-e145f6ad5670\", \"head\": \"Помолодел и стал жестким – глава Минздрава о четвертой волне коронавируса\", \"icon\": \"http://url.com/f28b5349-e639-4250-9391-7ad88fcf4946.jpg\", \"type\": \"http://url.com/info.png\", \"location\": \"Беларусь\" }, { \"id\": \"c2833cef-2928-11ec-a3ee-e145f6ad5670\", \"head\": \"Так было или не было? Серега ответил о своем романе с Бузовой\", \"icon\": \"http://url.com/10-2021/60cc9d51-f570-4e68-bada-4ba4aab92bcb.jpg\", \"type\": \"http://url.com/info.png\", \"location\": \"Минск\" }, { \"id\": \"6088c966-2920-11ec-a3ee-e145f6ad5670\", \"head\": \"Работа ТЭЦ в Минске восстановлена - Минэнерго\", \"icon\": \"http://url.com/01b6db5f-8305-4e86-9d9a-f59cc2be2787.jpg\", \"type\": \"http://url.com/info.png\", \"location\": \"Минск\" } ]";

    public class LastNews{
        @SerializedName("id")
        public String id;
        @SerializedName("head")
        public String head;
        @SerializedName("icon")
        public String icon;
        @SerializedName("type")
        public String type;
        @SerializedName("location")
        public String location;
    }

    LinearLayout listNews = ViewCreator.linearLayout(context, null, -1);
    ArrayList<Object> news = Decoder.fromJsonArray(jsonNews, LastNews.class);
    for(int i = 0; i < news.size(); i++){

        LastNews lastNews = (LastNews) news.get(i);

        //crate view and add to "listNews"

    }

Error message is:

Sourced file: inline evaluation of: ``import android.widget.LinearLayout;         import android.widget.ScrollView;    . . . '' unknown error: can't load this type of class file : at Line: 75 : in file: inline evaluation of: ``import android.widget.LinearLayout;         import android.widget.ScrollView;    . . . '' : public class LastNews { 

Can you tell me if such an implementation is possible using BeanShell? If so, is it possible to have an example of such functionality?


Solution

  • Maybe, but not by sending the text of the class file. Java is a compiled language. You'd need to send the .class file, or the equivalent that the most recent android Java interpreter used (is it .dex still?). Then you'd need to load it via a custom class loader. Basically you're going to be doing dark magic and really need to know Java, it's class structure, and how the interpreter works to do it.

    A couple of warnings about this:

    1)It won't be allowed on Google play. Google does not allow dynamically loaded code in apps on their store.

    2)It's a massive security hole. This is part of why #1 is the case.

    3)It becomes a major source of bugs over time, as code changes. You now have to worry not just about "does my release work" but "does my release work with every possible version of this downloaded code it may need to interact with". And also "If a version was skipped, will the data structure still be compatible, even if a version was skipped". There's additional possibility for security bugs here.